基本块的调整与跳转指令的化简

目录

一、基本块的次序调整

1、为什么要对次序进行调整?

2、怎样调整?

3、实现步骤

(1)为基本块列表排序的抽象机的状态定义

(2)为基本块列表排序的抽象机的单步执行单体stepM

 (3)测试用例及结果

 二、跳转指令的化简

 1、如何化简

 2、实现步骤

 (1)将trace合并成一个stm列表

(2)利用滑动窗对stm语句列表逐个判断化简 


一、基本块的次序调整

1、为什么要对次序进行调整?

IR作为中间代码程序,为了方便转换为机器指令程序,要将原来stm list中的元素进一步简化,使其更接近机器指令。

在简化过程中需要将双分支跳转语句CJUMP(rop,ie1,ie2,label_t,l_labelf)转换成单分支跳转语句SJUMP(rop,ie1,ie2,label_t)。为了将CJUMP中的第二个跳转 f 去掉,需要将以LABEL lf 开头的基本快调整到CJUMP后面顺序执行。

为了尽可能的将直接跳转语句JUMP(ie,[label])删掉,需要将以LAEBL label开始的基本块调整到以JUMP(CONST 0,[label])结尾的基本块后面,如此就可以将JUMP(CONST 0,[label])语句删除。

2、怎样调整?

①对于CJUMP语句,将其 lf 分支所对应的基本块调到紧接其后。

②对于JUMP语句,将其要跳转的基本块调到紧接其后。

3、实现步骤

(1)为基本块列表排序的抽象机的状态定义

ML{*
val state_type = "state"
val vars = [("prog","(label * stm list) list"),
            ("trace","(label * stm list) list"),
            ("marked","label list")]
val _ = record_defs [] state_type vars
*}
  • prog存放抽象机要执行的对象,其类型是还未调整次序的基本块列表,当一个基本块被执行后,不会从prog中移除,而是被标记为“执行过”。
  • trace存放已经调整好次序的基本块列表,基本块被执行后就会放入trace,且不再改变次序。
  • marked存放被标记为“执行过”的基本块的标号。

(2)为基本块列表排序的抽象机的单步执行单体stepM

ML{*
fun stepM (label,body) = get_markedM -- get_traceM -- get_progM :|--
    (fn ((marked,trace),prog) => (let
        val new_marked = label::marked
        val next = next_of body
        val next_block =
           if (tb_defined next prog andalso (not (member next new_marked)))
           then (SOME (next,(tb_lookup next prog)))
           else (case (filter (fn (l,_) => 
                 (not (member l new_marked))) prog) of
                 (block::_) => SOME block
                | _ => NONE )
   in
     set_traceM ((label,body)::trace) |--
     set_markedM new_marked |--
     returnM next_block
   end))
*}
  • stepM (label,body) 获取基本块的label和stm list
  • get_markedM -- get_traceM -- get_progM 获取状态
  • ((marked,trace),prog)  marked初值为空,每执行一个基本块加入其起始标号
  • new_marked = label::marked 将当前执行的基本块起始标签加入进marked,并展示存放在new_marked
  • next = next_of body 通过函数next_of 计算得到要调整到正在被执行的基本块后面的那个基本块的标号。
  • tb_defined next prog 找到起始标号为next的基本块(匹配二元组第一元是否相等),如果存在返回true,不存在返回false。注意:标号为 _done 的基本块不存在prog中,故当next为_done 时返回false
  • if (tb_defined next prog andalso (not (member next new_marked))) 当标号存在且基本块未被执行过时为真,否则为假。为真时表示以next为起始标号的基本块可以调整到当前正在执行的基本块之后,即将以next为起始标号的基本块作为下一个被执行的基本块。
  •  then (SOME (next,(tb_lookup next prog))) 条件判断为真时返回将以next为起始标号的基本块设置为next_block的值。
  •  case (filter (fn (l,_) => 
                     (not (member l new_marked))) prog) of 利用过滤函数filter将列表prog中符合无名函数not (member l new_marked)条件为真的元素组成一个列表(就是将prog中还未执行过的基本块取出)
  •  (block::_) => SOME block
                    | _ => NONE  将case  of 中过滤后的值来做模式匹配,取出过滤后列表中的第一个元素,将其作为下一个将要执行的基本块。如果过滤后的是一个空列表(当正在被执行的基本块后面的那个基本块的标号是 _done时过滤后为空列表,即所有的基本块都被),返回NONE。
  • set_traceM ((label,body)::trace) |--
         set_markedM new_marked |--
         returnM next_block     更新状态trace:将刚刚执行完的基本块放入最终的结果。更新状态marked:将加上了当前基本块起始标号的new_marked作为最新的marked。返回下一个将要被执行的基本块next_block。
ML{*
fun next_of body =case hd(rev body) of
    JUMP (_,[a]) => a
   | CJUMP (_,_,_,_,a) => a
*}

 反转stm list,取第一个元素(跳转指令),获得跳转的目的基本块标号

ML{*
fun reorder blocks = let
   val (_,state{trace,...}) = runM stepM (hd blocks)
               (state {prog = blocks,trace = [], marked = []})
   val trace = trace |> rev
  in
    trace
  end
*}

对基本块列表利用runM stepM (hd blocks)逐个处理元素,取出调整次序后的结果trace

 (3)测试用例及结果

ML{*
val (blocks,_)= "s =0;i =0; N = 10;
while (i <=N) {s = s+i;i = i+1 }" 
|>  linearized_IR_of  
|> basic_blocks  (NL "_start")(NL "_done")
val trace = reorder blocks
*}

测试用例 

val blocks =
   [(NL "_start",
     [LABEL (NL "_start"), MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 8)), CONST 0),
      MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), CONST 0), MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 0)), CONST 10),
      JUMP (CONST 0, [IL 3])]),
    (IL 3, [LABEL (IL 3), CJUMP (LE, MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), MEM (BINOP (PLUS, TEMP (NT "base"), CONST 0)), IL 1, IL 2)]),
    (IL 1, [LABEL (IL 1),
            MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 8)),
                  BINOP (PLUS, MEM (BINOP (PLUS, TEMP (NT "base"), CONST 8)), MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)))),
            MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), BINOP (PLUS, MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), CONST 1)),
            JUMP (CONST 0, [IL 3])]),
    (IL 2, [LABEL (IL 2), JUMP (CONST 0, [NL "_done"])])]:
   (label * stm list) list
val trace =
   [(NL "_start",
     [LABEL (NL "_start"), MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 8)), CONST 0),
      MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), CONST 0), MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 0)), CONST 10),
      JUMP (CONST 0, [IL 3])]),
    (IL 3, [LABEL (IL 3), CJUMP (LE, MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), MEM (BINOP (PLUS, TEMP (NT "base"), CONST 0)), IL 1, IL 2)]),
    (IL 2, [LABEL (IL 2), JUMP (CONST 0, [NL "_done"])]),
    (IL 1, [LABEL (IL 1),
            MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 8)),
                  BINOP (PLUS, MEM (BINOP (PLUS, TEMP (NT "base"), CONST 8)), MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)))),
            MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), BINOP (PLUS, MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), CONST 1)),
            JUMP (CONST 0, [IL 3])])]:
   (label * stm list) list

 运行结果

 二、跳转指令的化简

 1、如何化简

  1. 所有CJUMP(rop,ie1,ie2,lt,lf)匹配化简成SJUMP(rop,ie1,ie2,lt)
  2. 若JUMP(rop,[label])中的label与其后的基本块的起始标号相同,则删去这一条JUMP,否则保留JUMP

 2、实现步骤

总思路:1、将调整好次序的基本块列表trace取每个元素的body。2、将所有的body合并成一个stm语句列表。3、设置一个大小为2的滑动窗( [a,b]),对合并后的stm列表逐个进行判读

 (1)将trace合并成一个stm列表

取trace里每个元素的body

fun twotolist (label,body) = body

 将所有的body合并成一个stm列表

fun tolist trace = flat (map twotolist trace)

(2)利用滑动窗对stm语句列表逐个判断化简 



ML{*
fun c_jump [a,b] = case [a,b] of
     [CJUMP (r,i1,i2,l1,l2),LABEL l3] => if l2 = l3 then  [SJUMP (r,i1,i2,l1)] else  [SJUMP (r,i1,i2,l1),JUMP (CONST 0, [l2])]
   | [JUMP (r,[l1]),LABEL l2] => if l1 = l2 then [] else [a]
   | [_,_] => [a]
*}
ML{*
fun clear_f f (a::[]) = [[a]]
   | clear_f f (a::b::xs) = f [a,b] :: clear_f f (b::xs)
*}
ML{*
val g = clear_f c_jump it
*}
ML{*
fun clear trace = flat (clear_f c_jump (tolist trace))
*}
  •  fun c_jump [a,b] 对滑动窗内的第一个元素做修改,将修改后的元素封装成列表返回,方便后面删除JUMP,如果是CJUMP后面就是判断条件为错误的语句块则改成SJUMP,如果后面不是判断条件为错误的语句块则要加一条JUMP跳转到错误的语句。如果是JUMP且下一条语句是LABEL,则看其跳转标号与相邻的下一条LABEL语句的标号是否相同,相同则返回空列表,不同则保持原样。
  • fun clear_f 将大小为2的滑动窗在stm列表中一次滑动一个元素,并对窗体内的元素逐个执行函数 f ,将函数 f 返回的值组成一个列表。
  • fun clear trace = flat (clear_f c_jump (tolist trace)) 因为函数clear_f 执行后得到的是一个列表的列表,所以最后用 flat 合并成一个stm语句列表。

(3)测试用例及结果

ML{*
fun simplified_IR_of source = 
let
   val (blocks,_) = divided_IR_of source;
   val trace = reorder blocks
in
   clear trace
end
*}

peep{*
s = 0;
i = 1;
while i <= 10 {
  s = s + i;
  i = i + 1
}
*}

ML{*
val it = the_source() |> simplified_IR_of 
*}

 测试用例

val it = [LABEL (NL "_start"), MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), CONST 0),
          MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 0)), CONST 1), LABEL (IL 3),
          SJUMP (LE, MEM (BINOP (PLUS, TEMP (NT "base"), CONST 0)), CONST 10, IL 1), LABEL (IL 2), JUMP (CONST 0, [NL "_done"]), LABEL (IL 1),
          MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)),
                BINOP (PLUS, MEM (BINOP (PLUS, TEMP (NT "base"), CONST 4)), MEM (BINOP (PLUS, TEMP (NT "base"), CONST 0)))),
          MOVE (MEM (BINOP (PLUS, TEMP (NT "base"), CONST 0)), BINOP (PLUS, MEM (BINOP (PLUS, TEMP (NT "base"), CONST 0)), CONST 1)),
          JUMP (CONST 0, [IL 3])]:
   stm list

 结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值