# include <iostream>
# include <algorithm>
#include <array>
# include <cassert>
#include <cctype>
#include <climits>
#include <numeric>
# include <vector>
# include <string>
# include <set>
# include <map>
# include <cmath>
# include <iomanip>
# include <functional>
# include <tuple>
# include <utility>
# include <stack>
# include <queue>
# include <list>
# include <bitset>
# include <complex>
# include <chrono>
# include <random>
# include <limits.h>
# include <unordered_map>
# include <unordered_set>
# include <deque>
# include <cstdio>
# include <cstring>
#include <stdio.h>
#include<time.h>
#include <stdlib.h>
#include <cstdint>
#include <cfenv>
#include<fstream>
//#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
long long MOD = 998244353;//1000000000 + 7 998244353 924844033 1000000000 + 9;
constexpr long long INF = numeric_limits<LL>::max();
const double PI = acos(-1);
#define fir first
#define sec second
#define thi third
#define debug(x) cerr<<#x<<": "<<x<<'\n'
typedef pair<LL, LL> Pll;
typedef pair<double, double> Dll;
typedef pair<LL, pair<LL, LL>> Ppll;
typedef pair<LL, pair<LL, bitset<100001>>> Pbll;
typedef pair<LL, pair<LL, vector<LL>>> Pvll;
typedef pair<LL, LL> Vec2;
struct Tll { LL first, second, third; };
struct Fll { LL first, second, third, fourth; };
typedef pair<LL, Tll> Ptll;
#define rep(i,rept) for(LL i=0;i<rept;i++)
#define Rrep(i,mf) for(LL i=mf-1;i>=0;i--)
void YN(bool f) {
	if (f)
		cout << "YES" << endl;
	else
		cout << "NO" << endl;
}
void yn(bool f) {
	if (f)
		cout << "Yes" << endl;
	else
		cout << "No" << endl;
}
struct Edge { LL to, cost; };
struct edge {
	LL from, to, cost;
};
vector<vector<LL>>g;
vector<edge>ed;
vector<Pll>pv;
set<LL>st;
map<Pll, LL>ma;
int di[4][2] = { { 0,1 },{ 1,0 },{ 0,-1 },{ -1,0 } };
string str, ss;
bool f;

template<class T>struct matrix {
	int n = 0, m = 0;
	vector<vector<T>>mat;
	matrix() {}
	matrix(int _n) {
		mat.resize(_n);
		for (int i = 0; i < _n; i++)
			mat[i].resize(_n);
		n = _n;
		m = _n;
	}
	matrix(int _n, int _m) {
		mat.resize(_n);
		for (int i = 0; i < _n; i++)
			mat[i].resize(_m);
		n = _n;
		m = _m;
	}
	int GetRank() {
		int h = mat.size(), w = mat[0].size();
		int res = 0, now = 0;
		for (int i = 0; i < h; i++) {
			T ma = 0.0;
			int pivot;
			for (int j = i; j < h; j++) {
				if (mat[j][now] > ma) {
					ma = mat[j][now];
					pivot = j;
				}
			}
			if (ma == 0.0) {
				now++;
				if (now == w) break;
				i--;
				continue;
			}
			if (pivot != i) {
				for (int j = 0; j < w; j++) {
					swap(mat[i][j], mat[pivot][j]);
				}
			}
			T tmp = 1.0 / mat[i][now];
			for (int j = 0; j < w; j++) mat[i][j] *= tmp;
			for (int j = 0; j < h; j++) {
				if (i != j) {
					T tmp2 = mat[j][now];
					for (int k = 0; k < w; k++) {
						mat[j][k] -= mat[i][k] * tmp2;
					}
				}
			}
			res++;
		}
		return res;
	}
	bool Inv(matrix<T> &inv) {
		assert(mat.size() == mat[0].size() && inv.n == inv.m);
		int n = mat.size();
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				inv.mat[i][j] = (i == j ? 1.0 : 0.0);
			}
		}
		for (int i = 0; i < n; i++) {
			T ma = 0.0;
			int pivot;
			for (int j = i; j < n; j++) {
				if (mat[j][i] > ma) {
					ma = mat[j][i];
					pivot = j;
				}
			}
			if (ma == 0.0) return false;
			if (pivot != i) {
				for (int j = 0; j < n; j++) {
					swap(mat[i][j], mat[pivot][j]);
					swap(inv.mat[i][j], inv.mat[pivot][j]);
				}

			}
			T tmp = 1.0 / mat[i][i];
			for (int j = 0; j < n; j++) {
				mat[i][j] *= tmp;
				inv.mat[i][j] *= tmp;
			}
			for (int j = 0; j < n; j++) {
				if (i != j) {
					T tmp2 = mat[j][i];
					for (int k = 0; k < n; k++) {
						mat[j][k] -= mat[i][k] * tmp2;
						inv.mat[j][k] -= inv.mat[i][k] * tmp2;
					}
				}
			}
		}
		return true;
	}
	matrix<T> operator+(const matrix<T> &b) {
		assert(mat.size() == b.n && mat[0].size() == b.m);
		int h = mat.size(), w = mat[0].size();
		matrix<T> c(h, w);
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				c.mat[i][j] = mat[i][j] + b.mat[i][j];
			}
		}
		return c;
	}
	matrix<T> operator-(const matrix<T> &b) {
		assert(mat.size() == b.n&& mat[0].size() == b.m);
		int h = mat.size(), w = mat[0].size();
		matrix<T> c(h, w);
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				c.mat[i][j] = mat[i][j] - b.mat[i][j];
			}
		}
		return c;
	}
	matrix<T> operator*(const matrix<T> b) {
		assert(mat[0].size() == b.n);
		matrix<T> c(mat.size(), b.m);
		for (int i = 0; i < mat.size(); i++) {
			for (int k = 0; k < b.n; k++) {
				for (int j = 0; j < b.m; j++) {
					c.mat[i][j] = (c.mat[i][j] + mat[i][k] * b.mat[k][j]);
				}
			}
		}
		return c;
	}
	matrix<T> operator*(T b) {
		matrix<T> c(mat.size(), mat[0].size());
		for (int i = 0; i < mat.size(); i++) {
			for (int j = 0; j < mat[0].size(); j++) {
				c.mat[i][j] = mat[i][j] * b;
			}
		}
		return c;
	}
	matrix<T> Pow(long long n) {
		assert(mat.size() == mat[0].size());
		matrix<T> b(mat.size()), c(mat.size());
		c = *this;
		for (int i = 0; i < mat.size(); i++) {
			b.mat[i][i] = 1;
		}
		while (n > 0) {
			if (n & 1) b = b * c;
			c = c * c;
			n >>= 1;
		}
		return b;
	}
	T det() {
		T det = 1.0, buf;
		//三角行列を作成
		for (int i = 0; i<n; i++) {
			for (int j = 0; j<n; j++) {
				if (i<j) {
					buf = mat[j][i] / mat[i][i];
					for (int k = 0; k<n; k++) {
						mat[j][k] -= mat[i][k] * buf;
					}
				}
			}
		}

		//対角部分の積
		for (int i = 0; i<n; i++) {
			det *= mat[i][i];
		}
		return det;
	}
	matrix<T> rev() {
		matrix<T> inv_a(n, m), cp(n, m);
		for (int i = 0; i < n; i++)
			for (int j = 0; j < m; j++) {
				inv_a.mat[i][j] = mat[i][j];
				cp.mat[i][j] = mat[i][j];
			}
		T buf;
		//単位行列を作る
		for (int i = 0; i<n; i++) {
			for (int j = 0; j<n; j++) {
				inv_a.mat[i][j] = (i == j) ? 1.0 : 0.0;
			}
		}
		//掃き出し法
		for (int i = 0; i<n; i++) {
			buf = 1 / cp.mat[i][i];
			for (int j = 0; j<n; j++) {
				cp.mat[i][j] *= buf;
				inv_a.mat[i][j] *= buf;
			}
			for (int j = 0; j<n; j++) {
				if (i != j) {
					buf = cp.mat[j][i];
					for (int k = 0; k<n; k++) {
						cp.mat[j][k] -= cp.mat[i][k] * buf;
						inv_a.mat[j][k] -= inv_a.mat[i][k] * buf;
					}
				}
			}
		}
		return inv_a;
	}
};
int calc_rank(matrix<LL> &A) {
	int r = 0;
	for (int i = 0; i < A.m; ++i) {
		int pivot = -1;
		for (int j = r; j < A.n; ++j) {
			if (A.mat[j][i]) {
				pivot = j;
				break;
			}
		}
		if (pivot != -1) {
			swap(A.mat[pivot], A.mat[r]);
			for (int j = 0; j < A.n; ++j)
				if (j != r && A.mat[j][i])
				for(int k=0;k<A.m;k++)  A.mat[j][k] ^= A.mat[r][k];
			++r;
		}
	}
	return r;
}
LL n, m, s, t, h, w,mpow[810];
int main() {
	cin >> n >> m;
	mpow[0] = 1;
	rep(i, 800)mpow[i + 1] = mpow[i] * 2 % MOD;
	matrix<LL>mat(n, m);
	rep(i, n) {
		rep(j, m) {
			cin >> mat.mat[i][j];
		}
	}
	LL r = calc_rank(mat);
	cout << (mpow[n + m - 1] - mpow[n + m - r - 1] + MOD) % MOD << endl;
	return 0;
}


Measured memory_bytes: 1024