ssa: reuses slices for basicBlock.params (#2247)
This replaces the basicBlock.params field with the reusable
VarLength[Value] type. As a result, the compilation starts
using less memory and allocations.
```
goos: darwin
goarch: arm64
pkg: github.com/tetratelabs/wazero
│ old.txt │ new.txt │
│ sec/op │ sec/op vs base │
Compilation/wazero-10 2.004 ± 2% 2.001 ± 0% ~ (p=0.620 n=7)
Compilation/zig-10 4.164 ± 1% 4.174 ± 3% ~ (p=0.097 n=7)
geomean 2.888 2.890 +0.06%
│ old.txt │ new.txt │
│ B/op │ B/op vs base │
Compilation/wazero-10 297.7Mi ± 0% 297.5Mi ± 0% -0.06% (p=0.001 n=7)
Compilation/zig-10 594.0Mi ± 0% 593.9Mi ± 0% -0.01% (p=0.001 n=7)
geomean 420.5Mi 420.3Mi -0.03%
│ old.txt │ new.txt │
│ allocs/op │ allocs/op vs base │
Compilation/wazero-10 472.5k ± 0% 457.1k ± 0% -3.25% (p=0.001 n=7)
Compilation/zig-10 277.2k ± 0% 275.7k ± 0% -0.53% (p=0.001 n=7)
geomean 361.9k 355.0k -1.90%
```
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
@@ -81,7 +81,7 @@ type (
|
|||||||
rootInstr, currentInstr *Instruction
|
rootInstr, currentInstr *Instruction
|
||||||
// params are Values that represent parameters to a basicBlock.
|
// params are Values that represent parameters to a basicBlock.
|
||||||
// Each parameter can be considered as an output of PHI instruction in traditional SSA.
|
// Each parameter can be considered as an output of PHI instruction in traditional SSA.
|
||||||
params []Value
|
params Values
|
||||||
preds []basicBlockPredecessorInfo
|
preds []basicBlockPredecessorInfo
|
||||||
success []*basicBlock
|
success []*basicBlock
|
||||||
// singlePred is the alias to preds[0] for fast lookup, and only set after Seal is called.
|
// singlePred is the alias to preds[0] for fast lookup, and only set after Seal is called.
|
||||||
@@ -179,23 +179,23 @@ func (bb *basicBlock) ReturnBlock() bool {
|
|||||||
// AddParam implements BasicBlock.AddParam.
|
// AddParam implements BasicBlock.AddParam.
|
||||||
func (bb *basicBlock) AddParam(b Builder, typ Type) Value {
|
func (bb *basicBlock) AddParam(b Builder, typ Type) Value {
|
||||||
paramValue := b.allocateValue(typ)
|
paramValue := b.allocateValue(typ)
|
||||||
bb.params = append(bb.params, paramValue)
|
bb.params = bb.params.Append(&b.(*builder).varLengthPool, paramValue)
|
||||||
return paramValue
|
return paramValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// addParamOn adds a parameter to this block whose value is already allocated.
|
// addParamOn adds a parameter to this block whose value is already allocated.
|
||||||
func (bb *basicBlock) addParamOn(value Value) {
|
func (bb *basicBlock) addParamOn(b *builder, value Value) {
|
||||||
bb.params = append(bb.params, value)
|
bb.params = bb.params.Append(&b.varLengthPool, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Params implements BasicBlock.Params.
|
// Params implements BasicBlock.Params.
|
||||||
func (bb *basicBlock) Params() int {
|
func (bb *basicBlock) Params() int {
|
||||||
return len(bb.params)
|
return len(bb.params.View())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Param implements BasicBlock.Param.
|
// Param implements BasicBlock.Param.
|
||||||
func (bb *basicBlock) Param(i int) Value {
|
func (bb *basicBlock) Param(i int) Value {
|
||||||
return bb.params[i]
|
return bb.params.View()[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid implements BasicBlock.Valid.
|
// Valid implements BasicBlock.Valid.
|
||||||
@@ -268,7 +268,7 @@ func (bb *basicBlock) Tail() *Instruction {
|
|||||||
|
|
||||||
// reset resets the basicBlock to its initial state so that it can be reused for another function.
|
// reset resets the basicBlock to its initial state so that it can be reused for another function.
|
||||||
func resetBasicBlock(bb *basicBlock) {
|
func resetBasicBlock(bb *basicBlock) {
|
||||||
bb.params = bb.params[:0]
|
bb.params = ValuesNil
|
||||||
bb.rootInstr, bb.currentInstr = nil, nil
|
bb.rootInstr, bb.currentInstr = nil, nil
|
||||||
bb.preds = bb.preds[:0]
|
bb.preds = bb.preds[:0]
|
||||||
bb.success = bb.success[:0]
|
bb.success = bb.success[:0]
|
||||||
@@ -310,8 +310,8 @@ func (bb *basicBlock) addPred(blk BasicBlock, branch *Instruction) {
|
|||||||
|
|
||||||
// formatHeader returns the string representation of the header of the basicBlock.
|
// formatHeader returns the string representation of the header of the basicBlock.
|
||||||
func (bb *basicBlock) formatHeader(b Builder) string {
|
func (bb *basicBlock) formatHeader(b Builder) string {
|
||||||
ps := make([]string, len(bb.params))
|
ps := make([]string, len(bb.params.View()))
|
||||||
for i, p := range bb.params {
|
for i, p := range bb.params.View() {
|
||||||
ps[i] = p.formatWithType(b)
|
ps[i] = p.formatWithType(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,14 +349,14 @@ func (bb *basicBlock) validate(b *builder) {
|
|||||||
if bb.ReturnBlock() {
|
if bb.ReturnBlock() {
|
||||||
exp = len(b.currentSignature.Results)
|
exp = len(b.currentSignature.Results)
|
||||||
} else {
|
} else {
|
||||||
exp = len(bb.params)
|
exp = len(bb.params.View())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pred.branch.vs.View()) != exp {
|
if len(pred.branch.vs.View()) != exp {
|
||||||
panic(fmt.Sprintf(
|
panic(fmt.Sprintf(
|
||||||
"BUG: len(argument at %s) != len(params at %s): %d != %d: %s",
|
"BUG: len(argument at %s) != len(params at %s): %d != %d: %s",
|
||||||
pred.blk.Name(), bb.Name(),
|
pred.blk.Name(), bb.Name(),
|
||||||
len(pred.branch.vs.View()), len(bb.params), pred.branch.Format(b),
|
len(pred.branch.vs.View()), len(bb.params.View()), pred.branch.Format(b),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -543,7 +543,7 @@ func (b *builder) findValue(typ Type, variable Variable, blk *basicBlock) Value
|
|||||||
// Otherwise, add the tmpValue to this block as a parameter which may or may not be redundant, but
|
// Otherwise, add the tmpValue to this block as a parameter which may or may not be redundant, but
|
||||||
// later we eliminate trivial params in an optimization pass. This must be done before finding the
|
// later we eliminate trivial params in an optimization pass. This must be done before finding the
|
||||||
// definitions in the predecessors so that we can break the cycle.
|
// definitions in the predecessors so that we can break the cycle.
|
||||||
blk.addParamOn(tmpValue)
|
blk.addParamOn(b, tmpValue)
|
||||||
// After the new param is added, we have to manipulate the original branching instructions
|
// After the new param is added, we have to manipulate the original branching instructions
|
||||||
// in predecessors so that they would pass the definition of `variable` as the argument to
|
// in predecessors so that they would pass the definition of `variable` as the argument to
|
||||||
// the newly added PHI.
|
// the newly added PHI.
|
||||||
@@ -567,7 +567,7 @@ func (b *builder) Seal(raw BasicBlock) {
|
|||||||
for _, v := range blk.unknownValues {
|
for _, v := range blk.unknownValues {
|
||||||
variable, phiValue := v.variable, v.value
|
variable, phiValue := v.variable, v.value
|
||||||
typ := b.definedVariableType(variable)
|
typ := b.definedVariableType(variable)
|
||||||
blk.addParamOn(phiValue)
|
blk.addParamOn(b, phiValue)
|
||||||
for i := range blk.preds {
|
for i := range blk.preds {
|
||||||
pred := &blk.preds[i]
|
pred := &blk.preds[i]
|
||||||
predValue := b.findValue(typ, variable, pred.blk)
|
predValue := b.findValue(typ, variable, pred.blk)
|
||||||
|
|||||||
@@ -128,10 +128,11 @@ func passRedundantPhiEliminationOpt(b *builder) {
|
|||||||
_ = b.blockIteratorReversePostOrderBegin() // skip entry block!
|
_ = b.blockIteratorReversePostOrderBegin() // skip entry block!
|
||||||
// Below, we intentionally use the named iteration variable name, as this comes with inevitable nested for loops!
|
// Below, we intentionally use the named iteration variable name, as this comes with inevitable nested for loops!
|
||||||
for blk := b.blockIteratorReversePostOrderNext(); blk != nil; blk = b.blockIteratorReversePostOrderNext() {
|
for blk := b.blockIteratorReversePostOrderNext(); blk != nil; blk = b.blockIteratorReversePostOrderNext() {
|
||||||
paramNum := len(blk.params)
|
params := blk.params.View()
|
||||||
|
paramNum := len(params)
|
||||||
|
|
||||||
for paramIndex := 0; paramIndex < paramNum; paramIndex++ {
|
for paramIndex := 0; paramIndex < paramNum; paramIndex++ {
|
||||||
phiValue := blk.params[paramIndex]
|
phiValue := params[paramIndex]
|
||||||
redundant := true
|
redundant := true
|
||||||
|
|
||||||
nonSelfReferencingValue := ValueInvalid
|
nonSelfReferencingValue := ValueInvalid
|
||||||
@@ -189,7 +190,7 @@ func passRedundantPhiEliminationOpt(b *builder) {
|
|||||||
|
|
||||||
// Still need to have the definition of the value of the PHI (previously as the parameter).
|
// Still need to have the definition of the value of the PHI (previously as the parameter).
|
||||||
for _, redundantParamIndex := range redundantParameterIndexes {
|
for _, redundantParamIndex := range redundantParameterIndexes {
|
||||||
phiValue := blk.params[redundantParamIndex]
|
phiValue := params[redundantParamIndex]
|
||||||
onlyValue := b.redundantParameterIndexToValue[redundantParamIndex]
|
onlyValue := b.redundantParameterIndexToValue[redundantParamIndex]
|
||||||
// Create an alias in this block from the only phi argument to the phi value.
|
// Create an alias in this block from the only phi argument to the phi value.
|
||||||
b.alias(phiValue, onlyValue)
|
b.alias(phiValue, onlyValue)
|
||||||
@@ -198,13 +199,13 @@ func passRedundantPhiEliminationOpt(b *builder) {
|
|||||||
// Finally, Remove the param from the blk.
|
// Finally, Remove the param from the blk.
|
||||||
var cur int
|
var cur int
|
||||||
for paramIndex := 0; paramIndex < paramNum; paramIndex++ {
|
for paramIndex := 0; paramIndex < paramNum; paramIndex++ {
|
||||||
param := blk.params[paramIndex]
|
param := params[paramIndex]
|
||||||
if _, ok := b.redundantParameterIndexToValue[paramIndex]; !ok {
|
if _, ok := b.redundantParameterIndexToValue[paramIndex]; !ok {
|
||||||
blk.params[cur] = param
|
params[cur] = param
|
||||||
cur++
|
cur++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blk.params = blk.params[:cur]
|
blk.params.Cut(cur)
|
||||||
|
|
||||||
// Clears the map for the next iteration.
|
// Clears the map for the next iteration.
|
||||||
for _, paramIndex := range redundantParameterIndexes {
|
for _, paramIndex := range redundantParameterIndexes {
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ func (b *builder) splitCriticalEdge(pred, succ *basicBlock, predInfo *basicBlock
|
|||||||
trampoline.validate(b)
|
trampoline.validate(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(trampoline.params) > 0 {
|
if len(trampoline.params.View()) > 0 {
|
||||||
panic("trampoline should not have params")
|
panic("trampoline should not have params")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user