// tighten moves Values closer to the Blocks in which they are used. // This can reduce the amount of register spilling required, // if it doesn't also create more live values. // A Value can be moved to any block that // dominates all blocks in which it is used. func tighten(f *Func) { … } // phiTighten moves constants closer to phi users. // This pass avoids having lots of constants live for lots of the program. // See issue 16407. func phiTighten(f *Func) { … } // memState computes the memory state at the beginning and end of each block of // the function. The memory state is represented by a value of mem type. // The returned result is stored in startMem and endMem, and endMem is nil for // blocks with no successors (Exit,Ret,RetJmp blocks). This algorithm is not // suitable for infinite loop blocks that do not contain any mem operations. // For example: // b1: // // (some values) // // plain -> b2 // b2: <- b1 b2 // Plain -> b2 // // Algorithm introduction: // 1. The start memory state of a block is InitMem, a Phi node of type mem or // an incoming memory value. // 2. The start memory state of a block is consistent with the end memory state // of its parent nodes. If the start memory state of a block is a Phi value, // then the end memory state of its parent nodes is consistent with the // corresponding argument value of the Phi node. // 3. The algorithm first obtains the memory state of some blocks in the tree // in the first step. Then floods the known memory state to other nodes in // the second step. func memState(f *Func, startMem, endMem []*Value) { … }