COMPMID-1283: (GitHub issue) after convolution output data is zero

During the mutating passes accessors of optimized nodes were dropped
instead of being transfered to appropriate tensors.

Change-Id: I29183984d94806bdfb5c92af3acefd928c0fd171
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/136036
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
Tested-by: Jenkins <bsgcomp@arm.com>
diff --git a/src/graph/Tensor.cpp b/src/graph/Tensor.cpp
index 287e783..ef253fe 100644
--- a/src/graph/Tensor.cpp
+++ b/src/graph/Tensor.cpp
@@ -67,6 +67,11 @@
     return _accessor.get();
 }
 
+std::unique_ptr<ITensorAccessor> Tensor::extract_accessor()
+{
+    return std::move(_accessor);
+}
+
 bool Tensor::call_accessor()
 {
     // Early exit guard
diff --git a/src/graph/Utils.cpp b/src/graph/Utils.cpp
index 030fa2d..d5ca77d 100644
--- a/src/graph/Utils.cpp
+++ b/src/graph/Utils.cpp
@@ -80,8 +80,8 @@
 
     if(target != Target::GC)
     {
-        pm.append(support::cpp14::make_unique<InPlaceOperationMutator>());
         pm.append(support::cpp14::make_unique<NodeFusionMutator>());
+        pm.append(support::cpp14::make_unique<InPlaceOperationMutator>());
         pm.append(support::cpp14::make_unique<SplitLayerSubTensorMutator>());
         pm.append(support::cpp14::make_unique<DepthConcatSubTensorMutator>());
     }
diff --git a/src/graph/mutators/InPlaceOperationMutator.cpp b/src/graph/mutators/InPlaceOperationMutator.cpp
index bd3f098..31921b3 100644
--- a/src/graph/mutators/InPlaceOperationMutator.cpp
+++ b/src/graph/mutators/InPlaceOperationMutator.cpp
@@ -50,11 +50,26 @@
             // Check if parent has a single output if yes then force in place calculation else not
             if((input_edge != nullptr) && (input_edge->producer() != nullptr) && (input_edge->producer()->output_edges().size() == 1))
             {
-                ARM_COMPUTE_LOG_GRAPH_VERBOSE("Switching to in-place computation for the node with ID : "
-                                              << node->id() << " and name : " << node->name() << std::endl);
-                // Update output
-                auto tensor = input_edge->tensor();
-                node->set_output_tensor(tensor->id(), 0);
+                // Get current and new output tensors
+                auto current_output_tensor = node->output(0);
+                auto new_output_tensor     = input_edge->tensor();
+
+                ARM_COMPUTE_ERROR_ON(current_output_tensor == nullptr || new_output_tensor == nullptr);
+
+                // Prevent in-place operation if there is an accessor bound to the in-place tensor
+                if(new_output_tensor->accessor() == nullptr)
+                {
+                    ARM_COMPUTE_LOG_GRAPH_VERBOSE("Switching to in-place computation for the node with ID : "
+                                                  << node->id() << " and name : " << node->name() << std::endl);
+                    // Update accessor
+                    new_output_tensor->set_accessor(current_output_tensor->extract_accessor());
+                    // Update output
+                    node->set_output_tensor(new_output_tensor->id(), 0);
+                }
+                else
+                {
+                    ARM_COMPUTE_LOG_GRAPH_VERBOSE("Prevented in-place operation as there is an accessor bound to the input tensor\n");
+                }
             }
         }
     }
diff --git a/src/graph/mutators/NodeFusionMutator.cpp b/src/graph/mutators/NodeFusionMutator.cpp
index 2e893c2..39209d2 100644
--- a/src/graph/mutators/NodeFusionMutator.cpp
+++ b/src/graph/mutators/NodeFusionMutator.cpp
@@ -54,28 +54,45 @@
                 auto *bn_node  = arm_compute::utils::cast::polymorphic_downcast<BatchNormalizationLayerNode *>(output_edge->producer());
                 auto *act_node = arm_compute::utils::cast::polymorphic_downcast<ActivationLayerNode *>(output_edge->consumer());
 
-                // Get driving nodes of activation node
-                std::vector<NodeIdxPair> act_driving_nodes;
-                for(auto &act_output_edge_id : act_node->output_edges())
+                ARM_COMPUTE_ERROR_ON(act_node->output(0) == nullptr || bn_node->output(0) == nullptr);
+
+                // Prevent fusion if batch normalization node has an output accessor
+                if(bn_node->output(0)->accessor() == nullptr)
                 {
-                    auto act_output_edge = g.edge(act_output_edge_id);
-                    if(act_output_edge != nullptr)
+                    // Get driving nodes of activation node
+                    std::vector<NodeIdxPair> act_driving_nodes;
+                    for(auto &act_output_edge_id : act_node->output_edges())
                     {
-                        ARM_COMPUTE_ERROR_ON(act_output_edge->consumer() == nullptr);
-                        act_driving_nodes.push_back({ act_output_edge->consumer_id(), act_output_edge->consumer_idx() });
+                        auto act_output_edge = g.edge(act_output_edge_id);
+                        if(act_output_edge != nullptr)
+                        {
+                            ARM_COMPUTE_ERROR_ON(act_output_edge->consumer() == nullptr);
+                            act_driving_nodes.push_back(
+                            { act_output_edge->consumer_id(), act_output_edge->consumer_idx() });
+                        }
                     }
+
+                    // Set activation info to batch normalization
+                    bn_node->set_fused_activation(act_node->activation_info());
+
+                    // Extract activation node accessor if any
+                    auto act_node_accessor = act_node->output(0)->extract_accessor();
+
+                    // Remove activation node
+                    g.remove_node(act_node->id());
+
+                    // Update batch normalization node outputs
+                    for(auto &driving_node : act_driving_nodes)
+                    {
+                        g.add_connection(bn_node->id(), 0, driving_node.node_id, driving_node.index);
+                    }
+
+                    // Update accessor to batch normalization node
+                    bn_node->output(0)->set_accessor(std::move(act_node_accessor));
                 }
-
-                // Set activation info to batch normalization
-                bn_node->set_fused_activation(act_node->activation_info());
-
-                // Remove activation node
-                g.remove_node(act_node->id());
-
-                // Update batch normalization node outputs
-                for(auto &driving_node : act_driving_nodes)
+                else
                 {
-                    g.add_connection(bn_node->id(), 0, driving_node.node_id, driving_node.index);
+                    ARM_COMPUTE_LOG_GRAPH_VERBOSE("Prevented fusion as batch normalization node has an output accessor\n");
                 }
             }
         }