Skip to content

--spill-pointers fails on program #4721

@ChrisJefferson

Description

@ChrisJefferson

Below is a simple(ish) sudoku solver.

emcc a.cpp -o a.html produces a working program. If I then add wasm-opt a.wasm --spill-pointers -o a.wasm I get Uncaught RuntimeError: indirect call to null.

I started trying to reduce the program, but found many changes would fix the program, as (I think) the compiler is clever enough to optimise away the need for spilling pointers.

I could try to reduce the example further if that would be useful -- hopefully someone who knows more about wasm-opt might be able to figure out what's going on? --spill-pointers was re-added recently in #4570

I'm finding --spill-pointers fails on most large programs, this was one I found that was (I hope) small enough to be easily looked at, but big enough to fail.

// In this code we represent sudokus as a vector<vector<int> >, // where the value 0 means 'not yet known'. #include <vector> #include <iostream> #include <ostream> using namespace std; vector<int> check_sudoku_vector(vector<int> v); vector<vector<int> > check_sudoku(vector<vector<int> > sudoku); vector<vector<int> > read_sudoku(); void print_sudoku(vector<vector<int> > sudoku); void solve_sudoku(vector<vector<int> > sudoku); int main(void) { vector<vector<int> > v = read_sudoku(); solve_sudoku(v); } // Checks a vector does not contain any value twice // Attempts to fill in values where possible. // As a hack, we return the empty vector if there are // any repeated values. // This tries to fill in the blank value if it can. vector<int> check_sudoku_vector(vector<int> v) { // We need 10 because we want 1..9, and 0 for empty. vector<int> count(10); // Count up the occurrences of each value for(int i = 0; i < 9; ++i) count[v[i]]++; // Check if any value occurs twice for(int i = 1; i <= 9; ++i) { if(count[i] > 1) { // Some value occurs twice! vector<int> empty; return empty; } } if(count[0] == 1) { // There is exactly one value to fill in! int empty_place = -1; for(int i = 0; i < 9; ++i) { if(v[i] == 0) empty_place = i; } for(int i = 1; i <= 9; ++i) { if(count[i] == 0) { v[empty_place] = i; return v; } } } return v; } // Tries to fill in the sudoku. // returns the empty vector if a flaw is found. // Takes the return value of check_sudoku_vector and puts it back // in the sudoku. This might be a waste of time, or might fill in a value. // There are obviously other ways check_sudoku_vector could respond back, // this is just one example. vector<vector<int> > check_sudoku(vector<vector<int> > sudoku) { vector<vector<int> > empty_vector; // First check rows for(int i = 0; i < 9; ++i) { vector<int> v = check_sudoku_vector(sudoku[i]); if(v.empty()) { return empty_vector; } sudoku[i] = v; } // then columns for(int i = 0; i < 9; ++i) { vector<int> column; for(int j = 0; j < 9; ++j) column.push_back(sudoku[j][i]); vector<int> v = check_sudoku_vector(column); if(v.empty()) return empty_vector; for(int j = 0; j < 9; ++j) sudoku[j][i] = v[j]; } // then boxes. Notice we do some interesting // loop indexing! for(int i = 0; i < 9; i+=3) { for(int j = 0; j < 9; j+=3) { vector<int> box; for(int a = i; a < i + 3; ++a) for(int b = j; b < j + 3; ++b) box.push_back(sudoku[a][b]); vector<int> v = check_sudoku_vector(box); if(v.empty()) return empty_vector; // Put the values back in! int counter = 0; for(int a = i; a < i + 3; ++a) for(int b = j; b < j + 3; ++b) { sudoku[a][b] = v[counter]; counter++; } } } // The sudoku is fine! return sudoku; } vector<vector<int> > read_sudoku() { vector<vector<int> > v; for(int i = 0; i < 9; ++i) { vector<int> row; for(int j = 0; j < 9; ++j) { int val = 0; row.push_back(val); } v.push_back(row); } return v; } void print_sudoku(vector<vector<int> > sudoku) { for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) { cout << sudoku[i][j] << " "; } cout << endl; } cout << endl; exit(0); } int counter = 0; void solve_sudoku(vector<vector<int> > sudoku) { counter++; vector<vector<int> > sudoku_copy = check_sudoku(sudoku); // This means the sudoku is unsolvable if(sudoku_copy.empty()) return; // let's keep looping around until check_sudoku stops filling // in values! while(sudoku_copy != sudoku) { sudoku = sudoku_copy; sudoku_copy = check_sudoku(sudoku); if(sudoku_copy.empty()) return; } for(int i = 0; i < 9; ++i) { for(int j = 0; j < 9; ++j) { if(sudoku[i][j] == 0) { // We have found a value to branch on! for(int k = 1; k <= 9; ++k) { sudoku[i][j] = k; solve_sudoku(sudoku); } // No solution found here! return; } } } // if we get here, then the solution is complete! print_sudoku(sudoku); std::cout << "Search: " << counter << std::endl; } 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions