Register the outputs of hierarchical boundaries to contain critical paths within a single module or boundary. Consider registering the inputs also at the hierarchical boundaries. It is always easier to analyze and repair timing paths which lie within a module, rather than a path spanning multiple modules.
Synthesize any paths not registered at hierarchy boundaries. Rebuild the hierarchy or flatten it. This enables cross hierarchy optimization.
Registering the datapaths at logical boundaries helps retain traceability for debugging through the design process. Cross hierarchical optimizations are kept to a minimum. Logic does not move across modules.