#include <bits/stdc++.h>
#include <regex>
#ifdef _DEBUG
#include "debug.h"
#endif
//#define int ll
#define FOR(i, s, e) for (int i = int(s); i < int(e); ++i)
#define REP(i, e) FOR(i, 0, e)
#define mkpr make_pair
#define mktp make_tuple
#define tv(tp, i) get<(i)>(tp)
#define CLEAR(obj) obj = decltype(obj)()
#define var auto
#define OUT(type) type &
#define IN(type) const type &
#define self (*this)
#define in :
#define True true
#define False false
using namespace std; using str = string; using cstr = const str;
using ll = long long; using ull = unsigned long long; using cint = const int; using cll = const ll;
using vi = vector<int>; using vvi = vector<vi>; using vl = vector<ll>; using vvl = vector<vl>;
using vb = vector<bool>; using vvb = vector<vb>; using vd = vector<double>; using vvd = vector<vd>;
using vc = vector<char>; using vvc = vector<vc>; using vs = vector<string>;
using pii = pair<int, int>; using pll = pair<ll, ll>; using pdd = pair<double, double>; using psl = pair<string, ll>;
using tiii = tuple<int, int, int>; using tlll = tuple<ll, ll, ll>;
static const int MGN = 10; static const int ARYSZ_MAX = (int)1e7;
static const ll LINF = LLONG_MAX/2;
#ifdef int
static const int INF = LINF;
#else
static const int INF = INT_MAX/2;
#endif
static double EPS = 1e-9;
static inline bool DBLEQ(double a, double b) {return abs(a - b) < EPS;}
static inline void EPR(str msg) {cerr << msg << endl;}
static inline void AST(bool exp, str msg) {if(!exp){EPR(msg);} assert(exp);}
static inline void TAST(bool exp, str msg) {if(!exp){EPR(msg);} while(!exp){}}


struct BFS {
    int H, W;
    vs Gd;
    char Aisle, Wall;
    vi Dx, Dy;
    BFS(IN(vs) Grid, IN(vi) Dx = vi({0,1,0,-1}), IN(vi) Dy = vi({1,0,-1,0}),
        char Aisle='.', char Wall='#') {
        self.Gd = Grid;
        self.H = Grid.size(); self.W = Grid[0].size();
        self.Aisle = Aisle; self.Wall = Wall;
        self.Dx = Dx; self.Dy = Dy;
    }
    vvi dist;
    int shortest_dist(IN(pii)start, IN(pii)goal) {
        self.dist = vvi(self.H, vi(self.W, INF));
        queue<pii> que;
        que.push(start);
        int sx = start.first, sy = start.second;
        self.dist[sx][sy] = 0;
        while(que.empty() == False) {
            var pr = que.front(); que.pop();
            int x = pr.first, y = pr.second;
            REP(i,4) {
                int nx = x + self.Dx[i], ny = y + self.Dy[i];
                if (nx<0 or self.H<=nx or ny<0 or self.W<=ny)
                    continue;
                if (self.Gd[nx][ny] == self.Wall)
                    continue;
                if (self.dist[nx][ny] > self.dist[x][y] + 1) {
                    self.dist[nx][ny] = self.dist[x][y] + 1;
                    que.push(mkpr(nx, ny));
                }
            }
        }
        int gx = goal.first, gy = goal.second;
        if (self.dist[gx][gy] != INF)
            return self.dist[gx][gy];
        else
            return -1;
    }
};


int32_t main(int32_t argc, char* argv[]) {
    cin.tie(0);
    ios::sync_with_stdio(false);
#ifdef IMPORT_SAMPLE
    vs args(argv, argv+argc);
    string sample = make_sample(args, "sample-1");
    ifstream ifs(sample); cin.rdbuf(ifs.rdbuf());
#endif


    int H,W; cin>>H>>W;
    vs S(H); REP(i,H) cin>>S[i];

    int black = 0;
    REP(i,H)
        REP(j,W) if (S[i][j] == '#') black += 1;

    var bfs = BFS(S);
    int sdist = bfs.shortest_dist(mkpr(0,0), mkpr(H-1, W-1));

    int ans = -1;
    if (sdist >= 0) {
        ans = H*W - black - (sdist + 1);
    }
    cout << ans << endl;


    return 0;
}


Measured memory_bytes: 256