github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_copyelim.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 // CopyElim removes unnessecery register copies. 20 type CopyElim struct{} 21 22 func (CopyElim) Apply(cfg *CFG) { 23 regs := make(map[Reg]Reg) 24 consts := make(map[Reg]_ConstData) 25 26 /* constant zero registers */ 27 consts[Rz] = constint(0) 28 consts[Pn] = constptr(nil, Const) 29 30 /* register replacement func */ 31 replacereg := func(rr *Reg) { 32 var rv Reg 33 var ok bool 34 var cc _ConstData 35 36 /* substitute registers */ 37 for { 38 if rv, ok = regs[*rr]; ok { 39 *rr = rv 40 } else { 41 break 42 } 43 } 44 45 /* substitute zero registers */ 46 if cc, ok = consts[*rr]; ok { 47 if cc.i && cc.v == 0 { 48 *rr = Rz 49 } else if !cc.i && cc.p == nil { 50 *rr = Pn 51 } 52 } 53 } 54 55 /* Phase 1: Find all the constants */ 56 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 57 for _, v := range bb.Ins { 58 switch p := v.(type) { 59 case *IrConstInt: consts[p.R] = constint(p.V) 60 case *IrConstPtr: consts[p.R] = constptr(p.P, p.M) 61 } 62 } 63 }) 64 65 /* Phase 2: Identify all the identity operations */ 66 for _, bb := range cfg.PostOrder().Reversed() { 67 for _, v := range bb.Ins { 68 switch p := v.(type) { 69 default: { 70 continue 71 } 72 73 /* pointer arithmetic */ 74 case *IrLEA: { 75 if cc, ok := consts[p.Off]; ok && cc.i && cc.v == 0 { 76 regs[p.R] = p.Mem 77 } 78 } 79 80 /* integer arithmetic */ 81 case *IrBinaryExpr: { 82 var c bool 83 var i int64 84 var x _ConstData 85 var y _ConstData 86 87 /* calculate mathematical identities */ 88 switch p.Op { 89 case IrOpAdd : i = 0 90 case IrOpSub : i = 0 91 case IrOpMul : i = 1 92 case IrOpAnd : i = -1 93 case IrOpOr : i = 0 94 case IrOpXor : i = 0 95 case IrOpShr : i = 0 96 default : continue 97 } 98 99 /* check for identity operations */ 100 if x, c = consts[p.X]; c && x.i && x.v == i { 101 regs[p.R] = p.Y 102 } else if y, c = consts[p.Y]; c && y.i && y.v == i { 103 regs[p.R] = p.X 104 } 105 } 106 } 107 } 108 } 109 110 /* Phase 3: Replace all the register references */ 111 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 112 var ok bool 113 var use IrUsages 114 115 /* replace in Phi nodes */ 116 for _, v := range bb.Phi { 117 for _, u := range v.Usages() { 118 replacereg(u) 119 } 120 } 121 122 /* replace in instructions */ 123 for _, v := range bb.Ins { 124 if use, ok = v.(IrUsages); ok { 125 for _, u := range use.Usages() { 126 replacereg(u) 127 } 128 } 129 } 130 131 /* replace in terminators */ 132 if use, ok = bb.Term.(IrUsages); ok { 133 for _, u := range use.Usages() { 134 replacereg(u) 135 } 136 } 137 }) 138 }