macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let mut s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}
fn adjacent4(x: usize, y: usize, sx: usize, sy: usize) -> Vec<(usize, usize)> {
    [(-1, 0), (1, 0), (0, -1), (0, 1)]
        .into_iter()
        .filter_map(|&(dx, dy)| {
            let nx = x as isize + dx;
            let ny = y as isize + dy;
            if nx >= 0 && nx < sx as isize && ny >= 0 && ny < sy as isize {
                Some((nx as usize, ny as usize))
            } else {
                None
            }
        })
        .collect()
}

#[allow(unused_imports)]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
fn main() {
    input! {
        h: usize,
        w: usize,
        m: [chars; h],
    }
    let xw = vec![1, -1, 0, 0];
    let xy = vec![0, 0, 1, -1];
    let mut maze = m;
    let mut depth: Vec<Vec<i64>> = vec![vec![0; w]; h];
    let mut queue: VecDeque<(i32, i32)> = VecDeque::new();
    queue.push_back((0, 0));
    let mut count_white = 0;
    // 白いマスの数を数える処理
    for k in 0..h {
        count_white += (0..w).filter(|j| maze[k][*j] == '.').count();
    }
    // 最短経路を出す処理
    while let Some(v) = queue.pop_front() {
        let nowdepth = depth[v.1 as usize][v.0 as usize];
        if v.1 == h as i32 - 1 && v.0 == w as i32 - 1 {
            break;
        }

        for i in 0..4 {
            let nextx = v.0 - xw[i];
            let nexty = v.1 - xy[i];
            if nextx >= 0
                && nextx < w as i32
                && nexty >= 0
                && nexty < h as i32
                && maze[nexty as usize][nextx as usize] == '.'
            {
                maze[nexty as usize][nextx as usize] = '#';
                depth[nexty as usize][nextx as usize] = nowdepth + 1;
                queue.push_back((nextx, nexty));
            }
        }
    }

    // スタートからゴールにたどり着けない場合-1を出力
    // bfs終了後depth[h-1][w-1] == -1のとき
    if depth[h - 1][w - 1] == 0 {
        println!("-1")
    } else {
        println!("{}", count_white - depth[h - 1][w - 1] as usize - 1);
    }

    // 最短経路が存在する場合、白いマスの合計から最短経路の手数を引く
}


Measured memory_bytes: 4352