summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa
diff options
context:
space:
mode:
authorLibravatar Daenney <daenney@users.noreply.github.com>2024-06-12 14:21:34 +0200
committerLibravatar GitHub <noreply@github.com>2024-06-12 13:21:34 +0100
commit978b4176f1a31a497aaadd33f21659b318832c95 (patch)
tree8ab36617b993a457af5d2975bedaa63a57031ff3 /vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa
parent[bugfix] Correct Swagger path for poll voting (#2996) (diff)
downloadgotosocial-978b4176f1a31a497aaadd33f21659b318832c95.tar.xz
[chore] Upgrade wasm-sqlite to v0.16.2 (#2997)
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa')
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block.go73
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/builder.go104
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass.go41
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_blk_layouts.go16
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_cfg.go49
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/type.go3
6 files changed, 149 insertions, 137 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block.go
index 10b6b4b62..39627b989 100644
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block.go
+++ b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block.go
@@ -49,21 +49,12 @@ type BasicBlock interface {
// ReturnBlock returns ture if this block represents the function return.
ReturnBlock() bool
- // FormatHeader returns the debug string of this block, not including instruction.
- FormatHeader(b Builder) string
-
// Valid is true if this block is still valid even after optimizations.
Valid() bool
// Sealed is true if this block has been sealed.
Sealed() bool
- // BeginPredIterator returns the first predecessor of this block.
- BeginPredIterator() BasicBlock
-
- // NextPredIterator returns the next predecessor of this block.
- NextPredIterator() BasicBlock
-
// Preds returns the number of predecessors of this block.
Preds() int
@@ -88,10 +79,11 @@ type (
basicBlock struct {
id BasicBlockID
rootInstr, currentInstr *Instruction
- params []blockParam
- predIter int
- preds []basicBlockPredecessorInfo
- success []*basicBlock
+ // params are Values that represent parameters to a basicBlock.
+ // Each parameter can be considered as an output of PHI instruction in traditional SSA.
+ params []Value
+ preds []basicBlockPredecessorInfo
+ success []*basicBlock
// singlePred is the alias to preds[0] for fast lookup, and only set after Seal is called.
singlePred *basicBlock
// lastDefinitions maps Variable to its last definition in this block.
@@ -116,11 +108,14 @@ type (
// loopNestingForestChildren holds the children of this block in the loop nesting forest.
// Non-empty if and only if this block is a loop header (i.e. loopHeader=true)
- loopNestingForestChildren []BasicBlock
+ loopNestingForestChildren wazevoapi.VarLength[BasicBlock]
// reversePostOrder is used to sort all the blocks in the function in reverse post order.
// This is used in builder.LayoutBlocks.
- reversePostOrder int
+ reversePostOrder int32
+
+ // visited is used during various traversals.
+ visited int32
// child and sibling are the ones in the dominator tree.
child, sibling *basicBlock
@@ -128,15 +123,6 @@ type (
// BasicBlockID is the unique ID of a basicBlock.
BasicBlockID uint32
- // blockParam implements Value and represents a parameter to a basicBlock.
- blockParam struct {
- // value is the Value that corresponds to the parameter in this block,
- // and can be considered as an output of PHI instruction in traditional SSA.
- value Value
- // typ is the type of the parameter.
- typ Type
- }
-
unknownValue struct {
// variable is the variable that this unknownValue represents.
variable Variable
@@ -145,6 +131,9 @@ type (
}
)
+// basicBlockVarLengthNil is the default nil value for basicBlock.loopNestingForestChildren.
+var basicBlockVarLengthNil = wazevoapi.NewNilVarLength[BasicBlock]()
+
const basicBlockIDReturnBlock = 0xffffffff
// Name implements BasicBlock.Name.
@@ -190,13 +179,13 @@ func (bb *basicBlock) ReturnBlock() bool {
// AddParam implements BasicBlock.AddParam.
func (bb *basicBlock) AddParam(b Builder, typ Type) Value {
paramValue := b.allocateValue(typ)
- bb.params = append(bb.params, blockParam{typ: typ, value: paramValue})
+ bb.params = append(bb.params, paramValue)
return paramValue
}
// addParamOn adds a parameter to this block whose value is already allocated.
-func (bb *basicBlock) addParamOn(typ Type, value Value) {
- bb.params = append(bb.params, blockParam{typ: typ, value: value})
+func (bb *basicBlock) addParamOn(value Value) {
+ bb.params = append(bb.params, value)
}
// Params implements BasicBlock.Params.
@@ -206,8 +195,7 @@ func (bb *basicBlock) Params() int {
// Param implements BasicBlock.Param.
func (bb *basicBlock) Param(i int) Value {
- p := &bb.params[i]
- return p.value
+ return bb.params[i]
}
// Valid implements BasicBlock.Valid.
@@ -248,22 +236,6 @@ func (bb *basicBlock) NumPreds() int {
return len(bb.preds)
}
-// BeginPredIterator implements BasicBlock.BeginPredIterator.
-func (bb *basicBlock) BeginPredIterator() BasicBlock {
- bb.predIter = 0
- return bb.NextPredIterator()
-}
-
-// NextPredIterator implements BasicBlock.NextPredIterator.
-func (bb *basicBlock) NextPredIterator() BasicBlock {
- if bb.predIter >= len(bb.preds) {
- return nil
- }
- pred := bb.preds[bb.predIter].blk
- bb.predIter++
- return pred
-}
-
// Preds implements BasicBlock.Preds.
func (bb *basicBlock) Preds() int {
return len(bb.preds)
@@ -305,7 +277,8 @@ func resetBasicBlock(bb *basicBlock) {
bb.unknownValues = bb.unknownValues[:0]
bb.lastDefinitions = wazevoapi.ResetMap(bb.lastDefinitions)
bb.reversePostOrder = -1
- bb.loopNestingForestChildren = bb.loopNestingForestChildren[:0]
+ bb.visited = 0
+ bb.loopNestingForestChildren = basicBlockVarLengthNil
bb.loopHeader = false
bb.sibling = nil
bb.child = nil
@@ -335,11 +308,11 @@ func (bb *basicBlock) addPred(blk BasicBlock, branch *Instruction) {
pred.success = append(pred.success, bb)
}
-// FormatHeader implements BasicBlock.FormatHeader.
-func (bb *basicBlock) FormatHeader(b Builder) string {
+// formatHeader returns the string representation of the header of the basicBlock.
+func (bb *basicBlock) formatHeader(b Builder) string {
ps := make([]string, len(bb.params))
for i, p := range bb.params {
- ps[i] = p.value.formatWithType(b)
+ ps[i] = p.formatWithType(b)
}
if len(bb.preds) > 0 {
@@ -398,7 +371,7 @@ func (bb *basicBlock) String() string {
// LoopNestingForestChildren implements BasicBlock.LoopNestingForestChildren.
func (bb *basicBlock) LoopNestingForestChildren() []BasicBlock {
- return bb.loopNestingForestChildren
+ return bb.loopNestingForestChildren.View()
}
// LoopHeader implements BasicBlock.LoopHeader.
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/builder.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/builder.go
index 1fc84d2ea..0b700c4b1 100644
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/builder.go
+++ b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/builder.go
@@ -54,9 +54,6 @@ type Builder interface {
// MustFindValue searches the latest definition of the given Variable and returns the result.
MustFindValue(variable Variable) Value
- // MustFindValueInBlk is the same as MustFindValue except it searches the latest definition from the given BasicBlock.
- MustFindValueInBlk(variable Variable, blk BasicBlock) Value
-
// FindValueInLinearPath tries to find the latest definition of the given Variable in the linear path to the current BasicBlock.
// If it cannot find the definition, or it's not sealed yet, it returns ValueInvalid.
FindValueInLinearPath(variable Variable) Value
@@ -127,7 +124,11 @@ type Builder interface {
// Idom returns the immediate dominator of the given BasicBlock.
Idom(blk BasicBlock) BasicBlock
+ // VarLengthPool returns the VarLengthPool of Value.
VarLengthPool() *wazevoapi.VarLengthPool[Value]
+
+ // InsertZeroValue inserts a zero value constant instruction of the given type.
+ InsertZeroValue(t Type)
}
// NewBuilder returns a new Builder implementation.
@@ -135,10 +136,10 @@ func NewBuilder() Builder {
return &builder{
instructionsPool: wazevoapi.NewPool[Instruction](resetInstruction),
basicBlocksPool: wazevoapi.NewPool[basicBlock](resetBasicBlock),
+ varLengthBasicBlockPool: wazevoapi.NewVarLengthPool[BasicBlock](),
varLengthPool: wazevoapi.NewVarLengthPool[Value](),
valueAnnotations: make(map[ValueID]string),
signatures: make(map[SignatureID]*Signature),
- blkVisited: make(map[*basicBlock]int),
valueIDAliases: make(map[ValueID]Value),
redundantParameterIndexToValue: make(map[int]Value),
returnBlk: &basicBlock{id: basicBlockIDReturnBlock},
@@ -177,12 +178,13 @@ type builder struct {
dominators []*basicBlock
sparseTree dominatorSparseTree
+ varLengthBasicBlockPool wazevoapi.VarLengthPool[BasicBlock]
+
// loopNestingForestRoots are the roots of the loop nesting forest.
loopNestingForestRoots []BasicBlock
// The followings are used for optimization passes/deterministic compilation.
instStack []*Instruction
- blkVisited map[*basicBlock]int
valueIDToInstruction []*Instruction
blkStack []*basicBlock
blkStack2 []*basicBlock
@@ -200,6 +202,32 @@ type builder struct {
donePostBlockLayoutPasses bool
currentSourceOffset SourceOffset
+
+ // zeros are the zero value constants for each type.
+ zeros [typeEnd]Value
+}
+
+// InsertZeroValue implements Builder.InsertZeroValue.
+func (b *builder) InsertZeroValue(t Type) {
+ if b.zeros[t].Valid() {
+ return
+ }
+ zeroInst := b.AllocateInstruction()
+ switch t {
+ case TypeI32:
+ zeroInst.AsIconst32(0)
+ case TypeI64:
+ zeroInst.AsIconst64(0)
+ case TypeF32:
+ zeroInst.AsF32const(0)
+ case TypeF64:
+ zeroInst.AsF64const(0)
+ case TypeV128:
+ zeroInst.AsVconst(0, 0)
+ default:
+ panic("TODO: " + t.String())
+ }
+ b.zeros[t] = zeroInst.Insert(b).Return()
}
func (b *builder) VarLengthPool() *wazevoapi.VarLengthPool[Value] {
@@ -215,10 +243,12 @@ func (b *builder) ReturnBlock() BasicBlock {
func (b *builder) Init(s *Signature) {
b.nextVariable = 0
b.currentSignature = s
+ b.zeros = [typeEnd]Value{ValueInvalid, ValueInvalid, ValueInvalid, ValueInvalid, ValueInvalid, ValueInvalid}
resetBasicBlock(b.returnBlk)
b.instructionsPool.Reset()
b.basicBlocksPool.Reset()
b.varLengthPool.Reset()
+ b.varLengthBasicBlockPool.Reset()
b.donePreBlockLayoutPasses = false
b.doneBlockLayout = false
b.donePostBlockLayoutPasses = false
@@ -231,11 +261,6 @@ func (b *builder) Init(s *Signature) {
b.blkStack2 = b.blkStack2[:0]
b.dominators = b.dominators[:0]
b.loopNestingForestRoots = b.loopNestingForestRoots[:0]
-
- for i := 0; i < b.basicBlocksPool.Allocated(); i++ {
- blk := b.basicBlocksPool.View(i)
- delete(b.blkVisited, blk)
- }
b.basicBlocksPool.Reset()
for v := ValueID(0); v < b.nextValueID; v++ {
@@ -448,11 +473,6 @@ func (b *builder) findValueInLinearPath(variable Variable, blk *basicBlock) Valu
return ValueInvalid
}
-func (b *builder) MustFindValueInBlk(variable Variable, blk BasicBlock) Value {
- typ := b.definedVariableType(variable)
- return b.findValue(typ, variable, blk.(*basicBlock))
-}
-
// MustFindValue implements Builder.MustFindValue.
func (b *builder) MustFindValue(variable Variable) Value {
typ := b.definedVariableType(variable)
@@ -482,6 +502,9 @@ func (b *builder) findValue(typ Type, variable Variable, blk *basicBlock) Value
value: value,
})
return value
+ } else if blk.EntryBlock() {
+ // If this is the entry block, we reach the uninitialized variable which has zero value.
+ return b.zeros[b.definedVariableType(variable)]
}
if pred := blk.singlePred; pred != nil {
@@ -495,21 +518,42 @@ func (b *builder) findValue(typ Type, variable Variable, blk *basicBlock) Value
// If this block has multiple predecessors, we have to gather the definitions,
// and treat them as an argument to this block.
//
- // The first thing is to define a new parameter to this block which may or may not be redundant, but
- // 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.
- paramValue := blk.AddParam(b, typ)
- b.DefineVariable(variable, paramValue, blk)
-
- // 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
- // the newly added PHI.
+ // But before that, we have to check if the possible definitions are the same Value.
+ tmpValue := b.allocateValue(typ)
+ // Break the cycle by defining the variable with the tmpValue.
+ b.DefineVariable(variable, tmpValue, blk)
+ // Check all the predecessors if they have the same definition.
+ uniqueValue := ValueInvalid
for i := range blk.preds {
- pred := &blk.preds[i]
- value := b.findValue(typ, variable, pred.blk)
- pred.branch.addArgumentBranchInst(b, value)
+ predValue := b.findValue(typ, variable, blk.preds[i].blk)
+ if uniqueValue == ValueInvalid {
+ uniqueValue = predValue
+ } else if uniqueValue != predValue {
+ uniqueValue = ValueInvalid
+ break
+ }
+ }
+
+ if uniqueValue != ValueInvalid {
+ // If all the predecessors have the same definition, we can use that value.
+ b.DefineVariable(variable, uniqueValue, blk)
+ b.alias(tmpValue, uniqueValue)
+ return uniqueValue
+ } else {
+ // 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
+ // definitions in the predecessors so that we can break the cycle.
+ blk.addParamOn(tmpValue)
+ // 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
+ // the newly added PHI.
+ for i := range blk.preds {
+ pred := &blk.preds[i]
+ value := b.findValue(typ, variable, pred.blk)
+ pred.branch.addArgumentBranchInst(b, value)
+ }
+ return tmpValue
}
- return paramValue
}
// Seal implements Builder.Seal.
@@ -523,7 +567,7 @@ func (b *builder) Seal(raw BasicBlock) {
for _, v := range blk.unknownValues {
variable, phiValue := v.variable, v.value
typ := b.definedVariableType(variable)
- blk.addParamOn(typ, phiValue)
+ blk.addParamOn(phiValue)
for i := range blk.preds {
pred := &blk.preds[i]
predValue := b.findValue(typ, variable, pred.blk)
@@ -566,7 +610,7 @@ func (b *builder) Format() string {
}
for bb := iterBegin(); bb != nil; bb = iterNext() {
str.WriteByte('\n')
- str.WriteString(bb.FormatHeader(b))
+ str.WriteString(bb.formatHeader(b))
str.WriteByte('\n')
for cur := bb.Root(); cur != nil; cur = cur.Next() {
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass.go
index a2e986cd1..89ec34b7e 100644
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass.go
+++ b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass.go
@@ -22,9 +22,9 @@ func (b *builder) RunPasses() {
func (b *builder) runPreBlockLayoutPasses() {
passSortSuccessors(b)
passDeadBlockEliminationOpt(b)
- passRedundantPhiEliminationOpt(b)
// The result of passCalculateImmediateDominators will be used by various passes below.
passCalculateImmediateDominators(b)
+ passRedundantPhiEliminationOpt(b)
passNopInstElimination(b)
// TODO: implement either conversion of irreducible CFG into reducible one, or irreducible CFG detection where we panic.
@@ -78,12 +78,11 @@ func (b *builder) runFinalizingPasses() {
// passDeadBlockEliminationOpt searches the unreachable blocks, and sets the basicBlock.invalid flag true if so.
func passDeadBlockEliminationOpt(b *builder) {
entryBlk := b.entryBlk()
- b.clearBlkVisited()
b.blkStack = append(b.blkStack, entryBlk)
for len(b.blkStack) > 0 {
reachableBlk := b.blkStack[len(b.blkStack)-1]
b.blkStack = b.blkStack[:len(b.blkStack)-1]
- b.blkVisited[reachableBlk] = 0 // the value won't be used in this pass.
+ reachableBlk.visited = 1
if !reachableBlk.sealed && !reachableBlk.ReturnBlock() {
panic(fmt.Sprintf("%s is not sealed", reachableBlk))
@@ -94,7 +93,7 @@ func passDeadBlockEliminationOpt(b *builder) {
}
for _, succ := range reachableBlk.success {
- if _, ok := b.blkVisited[succ]; ok {
+ if succ.visited == 1 {
continue
}
b.blkStack = append(b.blkStack, succ)
@@ -102,13 +101,16 @@ func passDeadBlockEliminationOpt(b *builder) {
}
for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() {
- if _, ok := b.blkVisited[blk]; !ok {
+ if blk.visited != 1 {
blk.invalid = true
}
+ blk.visited = 0
}
}
// passRedundantPhiEliminationOpt eliminates the redundant PHIs (in our terminology, parameters of a block).
+// This requires the reverse post-order traversal to be calculated before calling this function,
+// hence passCalculateImmediateDominators must be called before this.
func passRedundantPhiEliminationOpt(b *builder) {
redundantParameterIndexes := b.ints[:0] // reuse the slice from previous iterations.
@@ -118,15 +120,18 @@ func passRedundantPhiEliminationOpt(b *builder) {
// relatively small. For example, sqlite speedtest binary results in the large number of redundant PHIs,
// the maximum number of iteration was 22, which seems to be acceptable but not that small either since the
// complexity here is O(BlockNum * Iterations) at the worst case where BlockNum might be the order of thousands.
+ // -- Note --
+ // Currently, each iteration can run in any order of blocks, but it empirically converges quickly in practice when
+ // running on the reverse post-order. It might be possible to optimize this further by using the dominator tree.
for {
changed := false
- _ = b.blockIteratorBegin() // 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!
- for blk := b.blockIteratorNext(); blk != nil; blk = b.blockIteratorNext() {
+ for blk := b.blockIteratorReversePostOrderNext(); blk != nil; blk = b.blockIteratorReversePostOrderNext() {
paramNum := len(blk.params)
for paramIndex := 0; paramIndex < paramNum; paramIndex++ {
- phiValue := blk.params[paramIndex].value
+ phiValue := blk.params[paramIndex]
redundant := true
nonSelfReferencingValue := ValueInvalid
@@ -184,7 +189,7 @@ func passRedundantPhiEliminationOpt(b *builder) {
// Still need to have the definition of the value of the PHI (previously as the parameter).
for _, redundantParamIndex := range redundantParameterIndexes {
- phiValue := blk.params[redundantParamIndex].value
+ phiValue := blk.params[redundantParamIndex]
onlyValue := b.redundantParameterIndexToValue[redundantParamIndex]
// Create an alias in this block from the only phi argument to the phi value.
b.alias(phiValue, onlyValue)
@@ -227,10 +232,10 @@ func passRedundantPhiEliminationOpt(b *builder) {
func passDeadCodeEliminationOpt(b *builder) {
nvid := int(b.nextValueID)
if nvid >= len(b.valueRefCounts) {
- b.valueRefCounts = append(b.valueRefCounts, make([]int, b.nextValueID)...)
+ b.valueRefCounts = append(b.valueRefCounts, make([]int, nvid-len(b.valueRefCounts)+1)...)
}
if nvid >= len(b.valueIDToInstruction) {
- b.valueIDToInstruction = append(b.valueIDToInstruction, make([]*Instruction, b.nextValueID)...)
+ b.valueIDToInstruction = append(b.valueIDToInstruction, make([]*Instruction, nvid-len(b.valueIDToInstruction)+1)...)
}
// First, we gather all the instructions with side effects.
@@ -350,22 +355,10 @@ func (b *builder) incRefCount(id ValueID, from *Instruction) {
b.valueRefCounts[id]++
}
-// clearBlkVisited clears the b.blkVisited map so that we can reuse it for multiple places.
-func (b *builder) clearBlkVisited() {
- b.blkStack2 = b.blkStack2[:0]
- for key := range b.blkVisited {
- b.blkStack2 = append(b.blkStack2, key)
- }
- for _, blk := range b.blkStack2 {
- delete(b.blkVisited, blk)
- }
- b.blkStack2 = b.blkStack2[:0]
-}
-
// passNopInstElimination eliminates the instructions which is essentially a no-op.
func passNopInstElimination(b *builder) {
if int(b.nextValueID) >= len(b.valueIDToInstruction) {
- b.valueIDToInstruction = append(b.valueIDToInstruction, make([]*Instruction, b.nextValueID)...)
+ b.valueIDToInstruction = append(b.valueIDToInstruction, make([]*Instruction, int(b.nextValueID)-len(b.valueIDToInstruction)+1)...)
}
for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() {
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_blk_layouts.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_blk_layouts.go
index 9068180a0..584b5eade 100644
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_blk_layouts.go
+++ b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_blk_layouts.go
@@ -23,8 +23,6 @@ import (
//
// This heuristic is done in maybeInvertBranches function.
func passLayoutBlocks(b *builder) {
- b.clearBlkVisited()
-
// We might end up splitting critical edges which adds more basic blocks,
// so we store the currently existing basic blocks in nonSplitBlocks temporarily.
// That way we can iterate over the original basic blocks while appending new ones into reversePostOrderedBasicBlocks.
@@ -47,20 +45,20 @@ func passLayoutBlocks(b *builder) {
for _, blk := range nonSplitBlocks {
for i := range blk.preds {
pred := blk.preds[i].blk
- if _, ok := b.blkVisited[pred]; ok || !pred.Valid() {
+ if pred.visited == 1 || !pred.Valid() {
continue
} else if pred.reversePostOrder < blk.reversePostOrder {
// This means the edge is critical, and this pred is the trampoline and yet to be inserted.
// Split edge trampolines must come before the destination in reverse post-order.
b.reversePostOrderedBasicBlocks = append(b.reversePostOrderedBasicBlocks, pred)
- b.blkVisited[pred] = 0 // mark as inserted, the value is not used.
+ pred.visited = 1 // mark as inserted.
}
}
// Now that we've already added all the potential trampoline blocks incoming to this block,
// we can add this block itself.
b.reversePostOrderedBasicBlocks = append(b.reversePostOrderedBasicBlocks, blk)
- b.blkVisited[blk] = 0 // mark as inserted, the value is not used.
+ blk.visited = 1 // mark as inserted.
if len(blk.success) < 2 {
// There won't be critical edge originating from this block.
@@ -116,7 +114,7 @@ func passLayoutBlocks(b *builder) {
if fallthroughBranch.opcode == OpcodeJump && fallthroughBranch.blk == trampoline {
// This can be lowered as fallthrough at the end of the block.
b.reversePostOrderedBasicBlocks = append(b.reversePostOrderedBasicBlocks, trampoline)
- b.blkVisited[trampoline] = 0 // mark as inserted, the value is not used.
+ trampoline.visited = 1 // mark as inserted.
} else {
uninsertedTrampolines = append(uninsertedTrampolines, trampoline)
}
@@ -126,7 +124,7 @@ func passLayoutBlocks(b *builder) {
if trampoline.success[0].reversePostOrder <= trampoline.reversePostOrder { // "<=", not "<" because the target might be itself.
// This means the critical edge was backward, so we insert after the current block immediately.
b.reversePostOrderedBasicBlocks = append(b.reversePostOrderedBasicBlocks, trampoline)
- b.blkVisited[trampoline] = 0 // mark as inserted, the value is not used.
+ trampoline.visited = 1 // mark as inserted.
} // If the target is forward, we can wait to insert until the target is inserted.
}
uninsertedTrampolines = uninsertedTrampolines[:0] // Reuse the stack for the next block.
@@ -142,8 +140,8 @@ func passLayoutBlocks(b *builder) {
if wazevoapi.SSAValidationEnabled {
for _, trampoline := range trampolines {
- if _, ok := b.blkVisited[trampoline]; !ok {
- panic("BUG: trampoline block not inserted: " + trampoline.FormatHeader(b))
+ if trampoline.visited != 1 {
+ panic("BUG: trampoline block not inserted: " + trampoline.formatHeader(b))
}
trampoline.validate(b)
}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_cfg.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_cfg.go
index 50cb9c475..e8288c4bd 100644
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_cfg.go
+++ b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_cfg.go
@@ -15,10 +15,6 @@ import (
// At the last of pass, this function also does the loop detection and sets the basicBlock.loop flag.
func passCalculateImmediateDominators(b *builder) {
reversePostOrder := b.reversePostOrderedBasicBlocks[:0]
- exploreStack := b.blkStack[:0]
- b.clearBlkVisited()
-
- entryBlk := b.entryBlk()
// Store the reverse postorder from the entrypoint into reversePostOrder slice.
// This calculation of reverse postorder is not described in the paper,
@@ -28,14 +24,17 @@ func passCalculateImmediateDominators(b *builder) {
// which is a reasonable assumption as long as SSA Builder is properly used.
//
// First we push blocks in postorder iteratively visit successors of the entry block.
- exploreStack = append(exploreStack, entryBlk)
+ entryBlk := b.entryBlk()
+ exploreStack := append(b.blkStack[:0], entryBlk)
+ // These flags are used to track the state of the block in the DFS traversal.
+ // We temporarily use the reversePostOrder field to store the state.
const visitStateUnseen, visitStateSeen, visitStateDone = 0, 1, 2
- b.blkVisited[entryBlk] = visitStateSeen
+ entryBlk.visited = visitStateSeen
for len(exploreStack) > 0 {
tail := len(exploreStack) - 1
blk := exploreStack[tail]
exploreStack = exploreStack[:tail]
- switch b.blkVisited[blk] {
+ switch blk.visited {
case visitStateUnseen:
// This is likely a bug in the frontend.
panic("BUG: unsupported CFG")
@@ -48,16 +47,18 @@ func passCalculateImmediateDominators(b *builder) {
if succ.ReturnBlock() || succ.invalid {
continue
}
- if b.blkVisited[succ] == visitStateUnseen {
- b.blkVisited[succ] = visitStateSeen
+ if succ.visited == visitStateUnseen {
+ succ.visited = visitStateSeen
exploreStack = append(exploreStack, succ)
}
}
// Finally, we could pop this block once we pop all of its successors.
- b.blkVisited[blk] = visitStateDone
+ blk.visited = visitStateDone
case visitStateDone:
// Note: at this point we push blk in postorder despite its name.
reversePostOrder = append(reversePostOrder, blk)
+ default:
+ panic("BUG")
}
}
// At this point, reversePostOrder has postorder actually, so we reverse it.
@@ -67,7 +68,7 @@ func passCalculateImmediateDominators(b *builder) {
}
for i, blk := range reversePostOrder {
- blk.reversePostOrder = i
+ blk.reversePostOrder = int32(i)
}
// Reuse the dominators slice if possible from the previous computation of function.
@@ -180,7 +181,7 @@ func passBuildLoopNestingForest(b *builder) {
b.loopNestingForestRoots = append(b.loopNestingForestRoots, blk)
} else if n == ent {
} else if n.loopHeader {
- n.loopNestingForestChildren = append(n.loopNestingForestChildren, blk)
+ n.loopNestingForestChildren = n.loopNestingForestChildren.Append(&b.varLengthBasicBlockPool, blk)
}
}
@@ -193,7 +194,7 @@ func passBuildLoopNestingForest(b *builder) {
func printLoopNestingForest(root *basicBlock, depth int) {
fmt.Println(strings.Repeat("\t", depth), "loop nesting forest root:", root.ID())
- for _, child := range root.loopNestingForestChildren {
+ for _, child := range root.loopNestingForestChildren.View() {
fmt.Println(strings.Repeat("\t", depth+1), "child:", child.ID())
if child.LoopHeader() {
printLoopNestingForest(child.(*basicBlock), depth+2)
@@ -202,10 +203,10 @@ func printLoopNestingForest(root *basicBlock, depth int) {
}
type dominatorSparseTree struct {
- time int
+ time int32
euler []*basicBlock
- first, depth []int
- table [][]int
+ first, depth []int32
+ table [][]int32
}
// passBuildDominatorTree builds the dominator tree for the function, and constructs builder.sparseTree.
@@ -232,11 +233,11 @@ func passBuildDominatorTree(b *builder) {
n := b.basicBlocksPool.Allocated()
st := &b.sparseTree
st.euler = append(st.euler[:0], make([]*basicBlock, 2*n-1)...)
- st.first = append(st.first[:0], make([]int, n)...)
+ st.first = append(st.first[:0], make([]int32, n)...)
for i := range st.first {
st.first[i] = -1
}
- st.depth = append(st.depth[:0], make([]int, 2*n-1)...)
+ st.depth = append(st.depth[:0], make([]int32, 2*n-1)...)
st.time = 0
// Start building the sparse tree.
@@ -244,9 +245,9 @@ func passBuildDominatorTree(b *builder) {
st.buildSparseTable()
}
-func (dt *dominatorSparseTree) eulerTour(node *basicBlock, height int) {
+func (dt *dominatorSparseTree) eulerTour(node *basicBlock, height int32) {
if wazevoapi.SSALoggingEnabled {
- fmt.Println(strings.Repeat("\t", height), "euler tour:", node.ID())
+ fmt.Println(strings.Repeat("\t", int(height)), "euler tour:", node.ID())
}
dt.euler[dt.time] = node
dt.depth[dt.time] = height
@@ -270,13 +271,13 @@ func (dt *dominatorSparseTree) buildSparseTable() {
table := dt.table
if n >= len(table) {
- table = append(table, make([][]int, n+1)...)
+ table = append(table, make([][]int32, n-len(table)+1)...)
}
for i := range table {
if len(table[i]) < k {
- table[i] = append(table[i], make([]int, k)...)
+ table[i] = append(table[i], make([]int32, k-len(table[i]))...)
}
- table[i][0] = i
+ table[i][0] = int32(i)
}
for j := 1; 1<<j <= n; j++ {
@@ -292,7 +293,7 @@ func (dt *dominatorSparseTree) buildSparseTable() {
}
// rmq performs a range minimum query on the sparse table.
-func (dt *dominatorSparseTree) rmq(l, r int) int {
+func (dt *dominatorSparseTree) rmq(l, r int32) int32 {
table := dt.table
depth := dt.depth
j := int(math.Log2(float64(r - l + 1)))
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/type.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/type.go
index e8c8cd9de..73daf4269 100644
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/type.go
+++ b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/type.go
@@ -21,6 +21,9 @@ const (
// TypeV128 represents 128-bit SIMD vectors.
TypeV128
+
+ // -- Do not add new types after this line. ----
+ typeEnd
)
// String implements fmt.Stringer.