DG OPT (DGBuilder generateDesign())

DG code 规则

  1. Node的Pin的输入只有一条,但是输出可能会有多条
  2. 删除edge,需要从dest node找edge,这是唯一的,src会有多条edges。
  3. Pin的操作三种:一是pin与pin直接connect连接(pin->connect(pin)),API会创建edge给两个pin;二是pin->connect(edge),该pin连接一个edge;三是pin->disconnect(edge),该pin与edge断开。
  4. 目前DG注意BasicBlock、loop(entry|exit)、每个框架里的node不可以悬空,要与parent连接。(每个operation node都要指定graph、ssrc、loop,data node只需要graph)
  5. ctrl边有就连接,目前逻辑运算应该涉及不多。

一、DGBuild的入口函数是:generateDesign();

bool DGBuilder::runOnModule(llvm::Module &m) {
  clock_t start_time = clock();
  generateDesign();
  clock_t end_time = clock();
  PrintTime(start_time, end_time, "DGBuilder");
  …………
}

二、generateDesign()内部处理流程

第一步:处理全局变量;
第二步:对IR中function进行排序。将排序后的FunctionList存在vector中。
第三步:遍历FunctionList,为其中每个function创建Graph,Graph *graph = generateGraph(func);并加入design_
第四步:将global nodes加入graph。

重点是第三步中的generateGraph()函数:


Graph* DGBuilder::generateGraph(llvm::Function *func){

  auto &LIWP = getAnalysis<llvm::LoopInfoWrapperPass>(*func);
  llvm::LoopInfo *LI = &LIWP.getLoopInfo();
//LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); // 利用getAnalysis函数获取该pass的一个指针。
  std::vector<llvm::BasicBlock*> bbs;
  std::unordered_map<llvm::BasicBlock*, OrderedSet<llvm::BasicBlock>> bb_preds;
  //analyse original block order info from IR, get topo-sorted blocks 'bbs' &
  //bb_preds: blocks that must be executed before it (including
  //both direct and indirect predecessors, not consider back circle)
	analyseOriginalBlockOrderInfo(func, LI, bbs, bb_preds);

#ifdef ESL_OUTLOG
  dumpOriginalCDAG(func, bbs);
#endif

  CompCtrlDep comp_ctrl_dep;//ctrl dependency 分析
  analyseCDG(func, comp_ctrl_dep, bbs);

  clock_t startT = clock();
  //data flow graph
  Graph* graph = createNodesAndDFG(func, bbs);
  clock_t endT = clock();
  PrintTime(startT, endT, "createDFG");
  //transform block order info to ssrc order info equally
	std::unordered_map<SSrcNode*, OrderedSet<SSrcNode>> bb_ssrc_preds;
	std::vector<std::pair<SSrcNode*, SSrcNode*> > bb_ssrc_pairs;
  getBlockSSrcOrderInfo(bbs, bb_preds, bb_ssrc_preds, bb_ssrc_pairs);

  formLoopInfo(graph, func, LI, bb_ssrc_preds);
  //添加ctrl edge
  addCtrlDepEdge(comp_ctrl_dep);

  startT = clock();
  addDataAccessOrderEdge(bbs, bb_ssrc_pairs);
  endT = clock();
  PrintTime(startT, endT, "addDataAccessOrderEdge");

  connectBlockSSrc(graph);
  connectLoopEntryExit(graph);
  connectGraphEntryExit(graph);

  startT = clock();
  buildConditionGraph(graph, comp_ctrl_dep);
  endT = clock();
  PrintTime(startT, endT, "buildConditionGraph");
  return graph;
}

三、如何打开dot文件

1、将 Graphviz .dot 文件转换为其他格式的图像
dot -Tpng main_stg.dot -o aaa.png
dot -Tpdf filename.dot -o outfile.pdf
其中,通过-Tpdf和-o参数指定输出文件名及格式。
2、打开图像
(1)xdg-open aaa.png
(2)eog (eye of gmone,是linux下内置的图片查看器。ubuntu16.04)
eog aaa.png

class Graph:

(1)getFunc,是哪个function
(2)getName
(3)遍历Ports
(4)遍历Nodes,起始为Entry Node,结束为Exit Node
(5)成员变量 如下

  Design* design_;
  std::string name_;
  std::vector<Port *> ports_;
  OrderedSet<Node> nodes_;  // The order is important, not including port
  Node *entry_;
  Node *exit_;
  // An auxiliary data structure to represents all loops in this graph
  LoopInfo *loop_info_;
  OrderedSet<CallingNode> call_sites_;
  llvm::Function* func_;

1、LoopInfo *getLoopInfo() const { return loop_info_; }
2、dumpCFG,dump BasicBlockNode and connected edges
3、dumpDFG all nodes and edges

class Node:

// The base class of all nodes, a node has inputs and outputs pins
// a back point to its owner graph, its parent loop
(1)NodeType中有CDFG_Port,port node作为graph的端口
(2)getOrderIn() node的输入pin;getOrderOut() node
的输出pin;
(3)TimingInfo *getTimingInfo() const { return timing_info_; }
(4)getGraph(),得到node所在graph
(5)SSrcNode *getDriverSSrc() const { return driver_ssrc_; } driver_ssrc是继承BasicBlock的做法,br跳转到BasicBlock,此时全部都是nodes,此时的driver_ssrc_就是这些nodes的统帅。
(6)int getNumInput() const { return inputs_.size(); } 其中input num第一个为输入pin(ctrl边),其余为Data的输入
(7)int getNumOutput() const { return outputs_.size(); } 其中output num第一个为输出pin(ctrl边),其余为Data的输出
(8)成员变量如下

  std::vector<Pin *> inputs_;
  std::vector<Pin *> outputs_;
private:
  std::string name_;
  Graph *graph_;
  Loop *parent_loop_;  // The parent Loop contains this node
  Object* hierarchy_obj_; //up hierarchy object(may be a graph, a loop, or a partitioned group)
  // if the node is inside a block, it has a driver_ssrc which is block entry ssrc
  SSrcNode *driver_ssrc_;

  TimingInfo *timing_info_;
  SimNode* sim_node_; //associated pointer to a Simulation Node

class Pin:

(1)bool isPointerType() const {return is_ptr_;}
(2)判断是否需要符号位扩展,edge两端是不同bit时,需要进行符号位扩展,pin上数据记录bit信息

  //signed extend value from this pin if needed
  bool isSigned() const {return is_signed_;}

(3)get和set Width,width则是多少bit的意思
(4)该Pin属于哪个node:Node *getOwner() const { return owner_; }
(5)pin与pin之间用edge互联

  /* there is one and only one edge between two pins */
  // Connect an edge to this pin
  void connect(Edge *edge);

(6)成员变量 如下

  typedef enum {
    OUT   = 0,
    IN    = 1,
  } Dir;
  
private:
  // Construct and destructor are private
  Pin(Node *owner, Dir dir, bool is_ptr) : owner_(owner),
                dir_(dir), width_(0), is_signed_(false), is_ptr_(is_ptr) { }
  ~Pin() {}
private:
  Dir dir_;
  int width_;
  Node *owner_;
  bool is_signed_;
  bool is_ptr_;
  OrderedSet<Edge> edges_;

class Edge:

(1)getType() 得到edge的属性
(2)Pin *getSrc()得到edge的src pin;Pin *getSink()得到edge的dest pin;
(3) Node *getSrcNode() const ; Node *getSinkNode() const ;
(4)int getDelay() edge的延迟
(5)int getWeight() edge的weight
(6)判断是Data边、CTRL边、memory边
(2)成员变量如下

  typedef enum {
    DATA       = 0,
    CTRL       = 1,
      MEMORY   = 2,
      CLOCK    = 3,
      RESOURCE = 4,
  } Type;
  //Only allowed to use pin->connect(pin) to create edge
  explicit Edge(Type type, int weight) :
    type_(type), src_(NULL), sink_(NULL),
		weight_(weight), delay_(0), attend_sche_(true), circle_back_(false) { }  
private:
  //type of this edge
  Type type_;
  //source and sink pin of this edge
  Pin *src_;
  Pin *sink_;
  int weight_; //latency of the edge
  int delay_; //delay of the edge: default value is zero

  bool attend_sche_; //whether form constraint in scheduling
  bool circle_back_; //whether is circle back edge
  

TimingInfo

// A node's timing info is decided by device
struct TimingInfo {
  TimingInfo(int lat, float delay) :
    latency_(lat), delay_(delay) { }
  ~TimingInfo() {}
  int latency_;
  float delay_;
};

PrintTime :

// void PrintTime(clock_t startT, clock_t endT, const std::string& Info){
//   double time  =(double)(endT - startT)/CLOCKS_PER_SEC;
//   std::cout  << "Finish " << Info <<". time: " << time << std::endl;
// }
  auto PrintTime = [](clock_t startT, clock_t endT, const std::string& Info) {
    double time  =(double)(endT - startT)/CLOCKS_PER_SEC;
    outs()  << "Finish " << Info <<". time: " << time << "\n";
  };
  clock_t start_time = clock();
  clock_t end_time = clock();
  PrintTime(start_time, end_time, "Time1");

FPGA中latency与delay概念的区别
latency出现在时序逻辑电路中,表示数据从输入到输出有效经过的时间,通常以时钟周期为单位。
latency:
输入数据与该数据经过处理后的结果输出之间的延时,是时钟延迟
一般以时钟为单位,指的是相对于某个时钟起始位置的1个或多个时钟后数据才有效
决定信号处理的响应速度

delay出现在组合逻辑电路、布线中,表示数据从一端到另一端经过的时间,通常以绝对时间衡量。
delay:
时序器件之间的逻辑延时,主要指器件延时、布线延时
是绝对的时间,指的是相对于时钟边沿的某个时间后数据才有效
决定电路的时钟频率,即运行频率

DG OPT:
1、创建节点(名字唯一,需要对node初始化:查看ElemWriteNode初始化)
2、设置节点属性(width)
3、连接数据边 (尽量自己重新创建edge进行连接)
4、连接控制边
5、删除旧的node

当一个node在BasicBlock中,当其为BB的pi时,需要连接BB的ssrc。
当一个node在loop中,当其为loop的pi时,需要连接loop的in,当其为loop的po时,需要连接loop的exit
当一个node在graph中,当其为graph的pi时,需要连接graph的in,当其为graph的po时,连接graph的exit

当mul&add转DSPnode时,暂不用考虑memory dependency边、br控制边,要考虑顺序边

目前判断mul和add时,确保他们的conditionNode一致才做转换,所创建的DSPnode全部放在加法node所在BB,最后需要连接loop边等。

利用check查看当前graph是否符合规矩
static void checkBoundaryConnection(Graph* graph);
static void checkBlockBoundary(Graph* graph);
static void checkLoopBoundary(Graph* graph);
static void checkGraphBoundary(Graph* graph);
static void removeNodeAndConnections(Node* node);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值