github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_comsubexpr.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 type _Vid interface { 24 IrDefinitions 25 vid() []string 26 } 27 28 func (self *IrLoadArg) vid() []string { 29 return []string { 30 fmt.Sprintf("#%d", self.I), 31 } 32 } 33 34 func (self *IrConstInt) vid() []string { 35 return []string { 36 fmt.Sprintf("$%d", self.V), 37 } 38 } 39 40 func (self *IrConstPtr) vid() []string { 41 return []string { 42 fmt.Sprintf("$%p", self.P), 43 } 44 } 45 46 func (self *IrLEA) vid() []string { 47 return []string { 48 fmt.Sprintf("(& %s %s)", self.Mem, self.Off), 49 } 50 } 51 52 func (self *IrUnaryExpr) vid() []string { 53 return []string { 54 fmt.Sprintf("(%s %s)", self.Op, self.V), 55 } 56 } 57 58 func (self *IrBinaryExpr) vid() []string { 59 x := self.X 60 y := self.Y 61 62 /* commutative operations, sort the operands */ 63 switch self.Op { 64 case IrOpAdd : fallthrough 65 case IrOpMul : fallthrough 66 case IrOpAnd : fallthrough 67 case IrOpOr : fallthrough 68 case IrOpXor : fallthrough 69 case IrCmpEq : fallthrough 70 case IrCmpNe : if x > y { x, y = y, x } 71 } 72 73 /* build the value ID */ 74 return []string { 75 fmt.Sprintf("(%s %s %s)", self.Op, x, y), 76 } 77 } 78 79 func (self *IrBitTestSet) vid() []string { 80 return []string { 81 fmt.Sprintf("(&# %s %s)", self.X, self.Y), 82 fmt.Sprintf("(|# %s %s)", self.X, self.Y), 83 } 84 } 85 86 type _VidMap struct { 87 p *_VidMap 88 m map[string]Reg 89 } 90 91 func (self *_VidMap) derive() *_VidMap { 92 return &_VidMap { 93 p: self, 94 m: make(map[string]Reg), 95 } 96 } 97 98 func (self *_VidMap) lookup(vid string) (Reg, bool) { 99 if r, ok := self.m[vid]; ok { 100 return r, true 101 } else if self.p == nil { 102 return 0, false 103 } else { 104 return self.p.lookup(vid) 105 } 106 } 107 108 func (self *_VidMap) define(vid string, reg Reg) { 109 self.m[vid] = reg 110 } 111 112 // CSE performs the Common Sub-expression Elimintation optimization. 113 type CSE struct{} 114 115 func (self CSE) dfs(cfg *CFG, bb *BasicBlock, vm *_VidMap) { 116 ins := bb.Ins 117 vals := vm.derive() 118 119 /* scan every instructions */ 120 for i, v := range ins { 121 var r Reg 122 var d _Vid 123 var ok bool 124 125 /* check if the instruction have VIDs */ 126 if d, ok = v.(_Vid); !ok { 127 continue 128 } 129 130 /* calculate the VIDs */ 131 repc := i 132 vids := d.vid() 133 defs := d.Definitions() 134 135 /* replace each VID with a copy instruction */ 136 for j, vid := range vids { 137 s := defs[j] 138 r, ok = vals.lookup(vid) 139 140 /* skip zero registers */ 141 if s.Kind() == K_zero { 142 continue 143 } 144 145 /* add to definations if not found */ 146 if !ok { 147 vals.define(vid, *s) 148 continue 149 } 150 151 /* allocate one slot for the new instruction */ 152 repc++ 153 bb.Ins = append(bb.Ins, nil) 154 copy(bb.Ins[repc + 1:], bb.Ins[repc:]) 155 156 /* insert a new copy instruction */ 157 bb.Ins[repc] = IrCopy(*s, r) 158 *s = s.Zero() 159 } 160 161 /* all the definations are been replaced */ 162 if repc == i + len(defs) { 163 bb.Ins = append(bb.Ins[:i], bb.Ins[i + 1:]...) 164 } 165 } 166 167 /* DFS the dominator tree */ 168 for _, v := range cfg.DominatorOf[bb.Id] { 169 self.dfs(cfg, v, vals) 170 } 171 } 172 173 func (self CSE) Apply(cfg *CFG) { 174 self.dfs(cfg, cfg.Root, nil) 175 }