github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_tdce.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 // TDCE removes trivial dead-code such as unused register definations from CFG. 20 type TDCE struct{} 21 22 func (TDCE) Apply(cfg *CFG) { 23 for { 24 done := true 25 decl := make(map[Reg]struct{}) 26 27 /* Phase 1: Mark all the definations */ 28 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 29 var ok bool 30 var defs IrDefinitions 31 32 /* mark all definations in Phi nodes */ 33 for _, v := range bb.Phi { 34 for _, r := range v.Definitions() { 35 decl[*r] = struct{}{} 36 } 37 } 38 39 /* mark all definations in instructions if any */ 40 for _, v := range bb.Ins { 41 if defs, ok = v.(IrDefinitions); ok { 42 for _, r := range defs.Definitions() { 43 decl[*r] = struct{}{} 44 } 45 } 46 } 47 48 /* mark all definations in terminators if any */ 49 if defs, ok = bb.Term.(IrDefinitions); ok { 50 for _, r := range defs.Definitions() { 51 decl[*r] = struct{}{} 52 } 53 } 54 }) 55 56 /* Phase 2: Find all register usages */ 57 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 58 var ok bool 59 var use IrUsages 60 61 /* mark all usages in Phi nodes */ 62 for _, v := range bb.Phi { 63 for _, r := range v.Usages() { 64 delete(decl, *r) 65 } 66 } 67 68 /* mark all usages in instructions if any */ 69 for _, v := range bb.Ins { 70 if use, ok = v.(IrUsages); ok { 71 for _, r := range use.Usages() { 72 delete(decl, *r) 73 } 74 } 75 } 76 77 /* mark usages in the terminator if any */ 78 if use, ok = bb.Term.(IrUsages); ok { 79 for _, r := range use.Usages() { 80 delete(decl, *r) 81 } 82 } 83 }) 84 85 /* Phase 3: Remove all unused declarations */ 86 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 87 var ok bool 88 var defs IrDefinitions 89 90 /* replace unused Phi assigments with zero registers */ 91 for _, v := range bb.Phi { 92 for _, r := range v.Definitions() { 93 if _, ok = decl[*r]; ok && r.Kind() != K_zero { 94 *r, done = r.Zero(), false 95 } 96 } 97 } 98 99 /* replace unused instruction assigments with zero registers */ 100 for _, v := range bb.Ins { 101 if defs, ok = v.(IrDefinitions); ok { 102 for _, r := range defs.Definitions() { 103 if _, ok = decl[*r]; ok && r.Kind() != K_zero { 104 *r, done = r.Zero(), false 105 } 106 } 107 } 108 } 109 110 /* replace unused terminator assigments with zero registers */ 111 if defs, ok = bb.Term.(IrDefinitions); ok { 112 for _, r := range defs.Definitions() { 113 if _, ok = decl[*r]; ok && r.Kind() != K_zero { 114 *r, done = r.Zero(), false 115 } 116 } 117 } 118 }) 119 120 /* Phase 4: Remove the entire defination if it's all zeros */ 121 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 122 phi, ins := bb.Phi, bb.Ins 123 bb.Phi, bb.Ins = bb.Phi[:0], bb.Ins[:0] 124 125 /* remove Phi nodes that don't have any effects */ 126 for _, v := range phi { 127 for _, r := range v.Definitions() { 128 if r.Kind() != K_zero { 129 bb.Phi = append(bb.Phi, v) 130 break 131 } 132 } 133 } 134 135 /* remove instructions that don't have any effects */ 136 for _, v := range ins { 137 if _, ok := v.(IrImpure); ok { 138 bb.Ins = append(bb.Ins, v) 139 } else if d, ok := v.(IrDefinitions); !ok { 140 bb.Ins = append(bb.Ins, v) 141 } else { 142 for _, r := range d.Definitions() { 143 if r.Kind() != K_zero { 144 bb.Ins = append(bb.Ins, v) 145 break 146 } 147 } 148 } 149 } 150 }) 151 152 /* no more modifications */ 153 if done { 154 break 155 } 156 } 157 }