-
Notifications
You must be signed in to change notification settings - Fork 42
Description
We believe there is an issue in how the memory operations are currently handled in Dynamatic. This issue is discussed in the following section. A possible solution is proposed afterward, and finally, the impact this change has on Dynamatic is discussed.
Problem definition
Firstly, keep in mind that the issue we would like to highlight exists for both types of memory operations. However, for simplicity, we focus on load operations in the description. Currently, in the pass CfToHandshake memory operations are converted from memref::LoadOp to either handshake::MCLoadOp or handshake::LSQLoadOp. As a result, the decision to choose between the memory controller and LSQ must be made in this pass. Moreover, the handshake::LSQLoadOp has a port named LSQLoadPort which needs to be connected to an LSQ, which forces us to instantiate the LSQ at this point. This process combines two logically distinct actions: (1) translating from CF to the Handshake representation and (2) connecting the memory operations to the chosen memory structure. We believe the two actions (ie. translation and connection) should ideally be separated into two different passes to maintain a clean and modular design.
One of the manifestations of this issue is the current implementation of Shrink it or Shred it!(ICFPT'19). This transformation is implemented in the Handshake MLIR because it requires the handshake structure. However, this pass also modifies memory connectivity (namely by removing LSQs or splitting a single LSQ into multiple LSQs). This highlights that these connections should ideally not have been established in the earlier transformation.
In conclusion, it appears that the decision on how to connect memory operations to memory controller or LSQ is premature. Thus, it makes more sense to postpone the connection to memory controller or LSQ until our knowledge is complete.
Possible solution
A possible solution is to introduce a new type of load (and also store) operation possibly named handshake::GeneralLoadOp, which would eventually be translated into either handshake::MCLoadOp or handshake::LSQLoadOp based on the annotated information. Another approach could be to introduce an entirely new dialect between CF and Handshake which holds the general operation. This would solve the inconsistency of having two types of Handshake representation (ie. one before the final translation and one after).
Impact
Implementing the proposed solution would have some impacts. Every pass that modifies the connectivity of memory operations should now annotate all the required information in handshake::GeneralLoadOp which would eventually be translated into handshake::MCLoadOp and handshake::LSQLoadOp. The advantage is that this transformation is done uniformly, regardless of the changes done by the previous passes. Previous passes can alter the result simply by modifying the annotation on the operation.
One of the passes that are affected, is --lower-cf-to-handshake, since it needs to convert CF operations into handshake::GeneralLoadOp. To instantiate the LSQ we need the dominance information which in turn requires the control flow information, so one of the things that should be preserved and carried through is the control flow information. Other required modifications are in --handshake-analyze-lsq-usage and --handshake-replace-memory-interfaces which implement Shrink it or Shred it!. The modification in these two passes mainly consists of not connecting the load operation into different ports, but instead annotating where it should be connected inside the operation. Finally, we believe that the proposed solution leaves all the other passes unchanged.
Given this proposed approach and its potential impacts, we would appreciate your thoughts and opinions on this solution.