github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_stack_liveness.go (about)

     1  /*
     2   * Copyright 2022 ByteDance Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package ssa
    18  
    19  import (
    20      `fmt`
    21  )
    22  
    23  // StackLiveness calculates the liveness of each stack slot.
    24  type StackLiveness struct{}
    25  
    26  func (self StackLiveness) livein(lr map[Pos]SlotSet, bb *BasicBlock, in map[int]SlotSet, out map[int]SlotSet) SlotSet {
    27      var ok bool
    28      var ss SlotSet
    29      var sp *IrSpill
    30  
    31      /* check for cached live-in sets */
    32      if ss, ok = in[bb.Id]; ok {
    33          return ss.clone()
    34      }
    35  
    36      /* calculate the live-out set of current block */
    37      tr := bb.Term
    38      sl := self.liveout(lr, bb, in, out).clone()
    39  
    40      /* assume all terminators are non-definitive */
    41      if _, ok = tr.(IrDefinitions); ok {
    42          panic("regalloc: definitions within terminators")
    43      }
    44  
    45      /* mark live range of the terminator */
    46      rr := sl.clone()
    47      lr[pos(bb, _P_term)] = rr
    48  
    49      /* live(i-1) = use(i) ∪ (live(i) - { def(i) }) */
    50      for i := len(bb.Ins) - 1; i >= 0; i-- {
    51          ins := bb.Ins[i]
    52          sp, ok = ins.(*IrSpill)
    53  
    54          /* only account for pointer slots */
    55          if !ok || !sp.S.IsPtr() {
    56              lr[pos(bb, i)] = sl.clone()
    57              continue
    58          }
    59  
    60          /* handle spill operations */
    61          switch sp.Op {
    62              default: {
    63                  panic("stackmap: invalid spill Op")
    64              }
    65  
    66              /* store operaion marks the value is alive since here */
    67              case IrSpillStore: {
    68                  if sl.remove(sp.S) {
    69                      lr[pos(bb, i)] = sl.clone()
    70                  } else {
    71                      panic(fmt.Sprintf("stackmap: killing non-existing value %s at %s:%d. ins = %s", sp.S, bb, i, bb.Ins[i]))
    72                  }
    73              }
    74  
    75              /* load operaion marks the value is alive until here */
    76              case IrSpillReload: {
    77                  if sl.add(sp.S) {
    78                      lr[pos(bb, i)] = sl.clone()
    79                  }
    80              }
    81          }
    82      }
    83  
    84      /* should not have any Phi nodes */
    85      if len(bb.Phi) != 0 {
    86          panic("regalloc: unexpected Phi nodes")
    87      }
    88  
    89      /* update the cache */
    90      in[bb.Id] = sl.clone()
    91      return sl
    92  }
    93  
    94  func (self StackLiveness) liveout(lr map[Pos]SlotSet, bb *BasicBlock, in map[int]SlotSet, out map[int]SlotSet) SlotSet {
    95      var ok bool
    96      var ss SlotSet
    97      var it IrSuccessors
    98  
    99      /* check for cached live-out sets */
   100      if ss, ok = out[bb.Id]; ok {
   101          return ss
   102      }
   103  
   104      /* check for return blocks */
   105      if _, ok = IrTryIntoArchReturn(bb.Term); ok {
   106          out[bb.Id] = make(SlotSet)
   107          return ss
   108      }
   109  
   110      /* create a new register set */
   111      ss = make(SlotSet)
   112      it = bb.Term.Successors()
   113  
   114      /* live-out(p) = ∑(live-in(succ(p))) */
   115      for out[bb.Id] = nil; it.Next(); {
   116          for sl := range self.livein(lr, it.Block(), in, out) {
   117              ss.add(sl)
   118          }
   119      }
   120  
   121      /* update cache */
   122      out[bb.Id] = ss
   123      return ss
   124  }
   125  
   126  func (self StackLiveness) liveness(cfg *CFG) {
   127      for ss := range self.livein(cfg.Func.Liveness, cfg.Root, make(map[int]SlotSet), make(map[int]SlotSet)) {
   128          panic("stackliveness: live slot at entry: " + ss.String())
   129      }
   130  }
   131  
   132  func (self StackLiveness) Apply(cfg *CFG) {
   133      cfg.Func.Liveness = make(map[Pos]SlotSet)
   134      self.liveness(cfg)
   135  }