From 75e9c1f7eb22ab57e741bf26690f2f6f3380ed94 Mon Sep 17 00:00:00 2001
From: Nora Abi Akar <nora.abiakar@gmail.com>
Date: Thu, 5 May 2022 09:20:05 +0200
Subject: [PATCH] modcc: Fix index generation

Ensure all indices into ABI variables are generated in dependency order, eg
```
idx = indices[iy]
foo = foos[ix]
```
---
 modcc/printer/cprinter.cpp   | 39 +++++++++++++++++++++++++++---------
 modcc/printer/gpuprinter.cpp | 39 +++++++++++++++++++++++++++---------
 2 files changed, 58 insertions(+), 20 deletions(-)

diff --git a/modcc/printer/cprinter.cpp b/modcc/printer/cprinter.cpp
index 2fc44fc8..2758e43c 100644
--- a/modcc/printer/cprinter.cpp
+++ b/modcc/printer/cprinter.cpp
@@ -516,23 +516,42 @@ namespace {
     };
 }
 
+// Return the indices that need to be read at the beginning
+// of an APIMethod in the order that they should be read
+// eg:
+//   node_index_ = node_index[i];
+//   domain_index_ = vec_di[node_index_];
 std::list<index_prop> gather_indexed_vars(const std::vector<LocalVariable*>& indexed_vars, const std::string& index) {
     std::list<index_prop> indices;
     for (auto& sym: indexed_vars) {
         auto d = decode_indexed_variable(sym->external_variable());
         if (!d.scalar()) {
             auto nested = !d.inner_index_var().empty();
-            auto outer_index_var = d.outer_index_var();
-            auto inner_index_var = nested? d.inner_index_var()+"i_": index;
-            index_prop index_var = {outer_index_var, inner_index_var, d.index_var_kind};
-            auto it = std::find(indices.begin(), indices.end(), index_var);
-            if (it == indices.end()) {
-                // If an inner index is required, push the outer index_var to the end of the list
-                if (nested) {
-                    indices.push_back(index_var);
+            if (nested) {
+                // Need to read 2 indices: outer[inner[index]]
+                index_prop inner_index_prop = {d.inner_index_var(), index, d.index_var_kind};
+                index_prop outer_index_prop = {d.outer_index_var(), d.inner_index_var()+"i_", d.index_var_kind};
+
+                // Check that the outer and inner indices haven't already been added to the list
+                auto inner_it = std::find(indices.begin(), indices.end(), inner_index_prop);
+                auto outer_it = std::find(indices.begin(), indices.end(), outer_index_prop);
+
+                // The inner index needs to be read before the outer index
+                if (inner_it == indices.end()) {
+                    indices.push_front(inner_index_prop);
                 }
-                else {
-                    indices.push_front(index_var);
+                if (outer_it == indices.end()) {
+                    indices.push_back(outer_index_prop);
+                }
+            }
+            else {
+                // Need to read 1 index: outer[index]
+                index_prop outer_index_prop = {d.outer_index_var(), index, d.index_var_kind};
+                auto it = std::find(indices.begin(), indices.end(), outer_index_prop);
+
+                // Check that the index hasn't already been added to the list
+                if (it == indices.end()) {
+                    indices.push_front(outer_index_prop);
                 }
             }
         }
diff --git a/modcc/printer/gpuprinter.cpp b/modcc/printer/gpuprinter.cpp
index d0a69873..63c04d5c 100644
--- a/modcc/printer/gpuprinter.cpp
+++ b/modcc/printer/gpuprinter.cpp
@@ -369,22 +369,41 @@ void emit_api_body_cu(std::ostream& out, APIMethod* e, bool is_point_proc, bool
         }
     };
 
+    // Gather the indices that need to be read at the beginning
+    // of an APIMethod in the order that they should be read
+    // eg:
+    //   node_index_ = node_index[tid];
+    //   domain_index_ = vec_di[node_index_];
     std::list<index_prop> indices;
     for (auto& sym: indexed_vars) {
         auto d = decode_indexed_variable(sym->external_variable());
         if (!d.scalar()) {
             auto nested = !d.inner_index_var().empty();
-            auto outer_index_var = d.outer_index_var();
-            auto inner_index_var = nested? index_i_name(d.inner_index_var()): "tid_";
-            index_prop index_var = {outer_index_var, inner_index_var};
-            auto it = std::find(indices.begin(), indices.end(), index_var);
-            if (it == indices.end()) {
-                // If an inner index is required, push the outer index_var to the end of the list
-                if (nested) {
-                    indices.push_back(index_var);
+            if (nested) {
+                // Need to read 2 indices: outer[inner[tid]]
+                index_prop inner_index_prop = {d.inner_index_var(), "tid_"};
+                index_prop outer_index_prop = {d.outer_index_var(), index_i_name(d.inner_index_var())};
+
+                // Check that the outer and inner indices haven't already been added to the list
+                auto inner_it = std::find(indices.begin(), indices.end(), inner_index_prop);
+                auto outer_it = std::find(indices.begin(), indices.end(), outer_index_prop);
+
+                // The inner index needs to be read before the outer index
+                if (inner_it == indices.end()) {
+                    indices.push_front(inner_index_prop);
                 }
-                else {
-                    indices.push_front(index_var);
+                if (outer_it == indices.end()) {
+                    indices.push_back(outer_index_prop);
+                }
+            }
+            else {
+                // Need to read 1 index: outer[index]
+                index_prop outer_index_prop = {d.outer_index_var(), "tid_"};
+
+                // Check that the index hasn't already been added to the list
+                auto it = std::find(indices.begin(), indices.end(), outer_index_prop);
+                if (it == indices.end()) {
+                    indices.push_front(outer_index_prop);
                 }
             }
         }
-- 
GitLab