diff options
author | 2024-08-15 00:08:55 +0000 | |
---|---|---|
committer | 2024-08-15 00:08:55 +0000 | |
commit | 09f24e044653b1327ac1c40f3ab150e3f0184f23 (patch) | |
tree | 1d9984d053fa5c8d1203abaa49b8752a1532ff11 /vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa | |
parent | update go-fastcopy to v1.1.3 (#3200) (diff) | |
download | gotosocial-09f24e044653b1327ac1c40f3ab150e3f0184f23.tar.xz |
update go-ffmpreg to v0.2.5 (pulls in latest tetratelabs/wazero) (#3203)
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa')
8 files changed, 228 insertions, 220 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 39627b989..cf7f14d3b 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 @@ -34,9 +34,6 @@ type BasicBlock interface { // The returned Value is the definition of the param in this block. Param(i int) Value - // InsertInstruction inserts an instruction that implements Value into the tail of this block. - InsertInstruction(raw *Instruction) - // Root returns the root instruction of this block. Root() *Instruction @@ -81,7 +78,7 @@ type ( rootInstr, currentInstr *Instruction // 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 + params Values preds []basicBlockPredecessorInfo success []*basicBlock // singlePred is the alias to preds[0] for fast lookup, and only set after Seal is called. @@ -179,23 +176,23 @@ 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, paramValue) + bb.params = bb.params.Append(&b.(*builder).varLengthPool, paramValue) return paramValue } // addParamOn adds a parameter to this block whose value is already allocated. -func (bb *basicBlock) addParamOn(value Value) { - bb.params = append(bb.params, value) +func (bb *basicBlock) addParamOn(b *builder, value Value) { + bb.params = bb.params.Append(&b.varLengthPool, value) } // Params implements BasicBlock.Params. func (bb *basicBlock) Params() int { - return len(bb.params) + return len(bb.params.View()) } // Param implements BasicBlock.Param. func (bb *basicBlock) Param(i int) Value { - return bb.params[i] + return bb.params.View()[i] } // Valid implements BasicBlock.Valid. @@ -208,8 +205,8 @@ func (bb *basicBlock) Sealed() bool { return bb.sealed } -// InsertInstruction implements BasicBlock.InsertInstruction. -func (bb *basicBlock) InsertInstruction(next *Instruction) { +// insertInstruction implements BasicBlock.InsertInstruction. +func (bb *basicBlock) insertInstruction(b *builder, next *Instruction) { current := bb.currentInstr if current != nil { current.next = next @@ -221,12 +218,12 @@ func (bb *basicBlock) InsertInstruction(next *Instruction) { switch next.opcode { case OpcodeJump, OpcodeBrz, OpcodeBrnz: - target := next.blk.(*basicBlock) - target.addPred(bb, next) + target := BasicBlockID(next.rValue) + b.basicBlock(target).addPred(bb, next) case OpcodeBrTable: - for _, _target := range next.targets { - target := _target.(*basicBlock) - target.addPred(bb, next) + for _, _target := range next.rValues.View() { + target := BasicBlockID(_target) + b.basicBlock(target).addPred(bb, next) } } } @@ -268,7 +265,7 @@ func (bb *basicBlock) Tail() *Instruction { // reset resets the basicBlock to its initial state so that it can be reused for another function. func resetBasicBlock(bb *basicBlock) { - bb.params = bb.params[:0] + bb.params = ValuesNil bb.rootInstr, bb.currentInstr = nil, nil bb.preds = bb.preds[:0] bb.success = bb.success[:0] @@ -310,8 +307,8 @@ func (bb *basicBlock) addPred(blk BasicBlock, branch *Instruction) { // 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 := make([]string, len(bb.params.View())) + for i, p := range bb.params.View() { ps[i] = p.formatWithType(b) } @@ -339,7 +336,9 @@ func (bb *basicBlock) validate(b *builder) { if len(bb.preds) > 0 { for _, pred := range bb.preds { if pred.branch.opcode != OpcodeBrTable { - if target := pred.branch.blk; target != bb { + blockID := int(pred.branch.rValue) + target := b.basicBlocksPool.View(blockID) + if target != bb { panic(fmt.Sprintf("BUG: '%s' is not branch to %s, but to %s", pred.branch.Format(b), bb.Name(), target.Name())) } @@ -349,14 +348,14 @@ func (bb *basicBlock) validate(b *builder) { if bb.ReturnBlock() { exp = len(b.currentSignature.Results) } else { - exp = len(bb.params) + exp = len(bb.params.View()) } if len(pred.branch.vs.View()) != exp { panic(fmt.Sprintf( "BUG: len(argument at %s) != len(params at %s): %d != %d: %s", 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), )) } diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort.go index e1471edc3..fb98298f7 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort.go +++ b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort.go @@ -1,5 +1,3 @@ -//go:build go1.21 - package ssa import ( diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort_old.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort_old.go deleted file mode 100644 index 9dc881dae..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort_old.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build !go1.21 - -// TODO: delete after the floor Go version is 1.21 - -package ssa - -import "sort" - -func sortBlocks(blocks []*basicBlock) { - sort.SliceStable(blocks, func(i, j int) bool { - iBlk, jBlk := blocks[i], blocks[j] - if jBlk.ReturnBlock() { - return true - } - if iBlk.ReturnBlock() { - return false - } - iRoot, jRoot := iBlk.rootInstr, jBlk.rootInstr - if iRoot == nil || jRoot == nil { // For testing. - return true - } - return iBlk.rootInstr.id < jBlk.rootInstr.id - }) -} 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 0b700c4b1..43dd7d292 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 @@ -94,9 +94,9 @@ type Builder interface { // Returns nil if there's no unseen BasicBlock. BlockIteratorNext() BasicBlock - // ValueRefCounts returns the map of ValueID to its reference count. - // The returned slice must not be modified. - ValueRefCounts() []int + // ValuesInfo returns the data per Value used to lower the SSA in backend. + // This is indexed by ValueID. + ValuesInfo() []ValueInfo // BlockIteratorReversePostOrderBegin is almost the same as BlockIteratorBegin except it returns the BasicBlock in the reverse post-order. // This is available after RunPasses is run. @@ -129,20 +129,24 @@ type Builder interface { // InsertZeroValue inserts a zero value constant instruction of the given type. InsertZeroValue(t Type) + + // BasicBlock returns the BasicBlock of the given ID. + BasicBlock(id BasicBlockID) BasicBlock + + // InstructionOfValue returns the Instruction that produces the given Value or nil if the Value is not produced by any Instruction. + InstructionOfValue(v Value) *Instruction } // NewBuilder returns a new Builder implementation. 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), - valueIDAliases: make(map[ValueID]Value), - redundantParameterIndexToValue: make(map[int]Value), - returnBlk: &basicBlock{id: basicBlockIDReturnBlock}, + 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), + returnBlk: &basicBlock{id: basicBlockIDReturnBlock}, } } @@ -159,19 +163,16 @@ type builder struct { currentBB *basicBlock returnBlk *basicBlock - // variables track the types for Variable with the index regarded Variable. - variables []Type // nextValueID is used by builder.AllocateValue. nextValueID ValueID // nextVariable is used by builder.AllocateVariable. nextVariable Variable - valueIDAliases map[ValueID]Value + // valueAnnotations contains the annotations for each Value, only used for debugging. valueAnnotations map[ValueID]string - // valueRefCounts is used to lower the SSA in backend, and will be calculated - // by the last SSA-level optimization pass. - valueRefCounts []int + // valuesInfo contains the data per Value used to lower the SSA in backend. This is indexed by ValueID. + valuesInfo []ValueInfo // dominators stores the immediate dominator of each BasicBlock. // The index is blockID of the BasicBlock. @@ -184,12 +185,10 @@ type builder struct { loopNestingForestRoots []BasicBlock // The followings are used for optimization passes/deterministic compilation. - instStack []*Instruction - valueIDToInstruction []*Instruction - blkStack []*basicBlock - blkStack2 []*basicBlock - ints []int - redundantParameterIndexToValue map[int]Value + instStack []*Instruction + blkStack []*basicBlock + blkStack2 []*basicBlock + redundantParams []redundantParam // blockIterCur is used to implement blockIteratorBegin and blockIteratorNext. blockIterCur int @@ -207,6 +206,34 @@ type builder struct { zeros [typeEnd]Value } +// ValueInfo contains the data per Value used to lower the SSA in backend. +type ValueInfo struct { + // RefCount is the reference count of the Value. + RefCount uint32 + alias Value +} + +// redundantParam is a pair of the index of the redundant parameter and the Value. +// This is used to eliminate the redundant parameters in the optimization pass. +type redundantParam struct { + // index is the index of the redundant parameter in the basicBlock. + index int + // uniqueValue is the Value which is passed to the redundant parameter. + uniqueValue Value +} + +// BasicBlock implements Builder.BasicBlock. +func (b *builder) BasicBlock(id BasicBlockID) BasicBlock { + return b.basicBlock(id) +} + +func (b *builder) basicBlock(id BasicBlockID) *basicBlock { + if id == basicBlockIDReturnBlock { + return b.returnBlk + } + return b.basicBlocksPool.View(int(id)) +} + // InsertZeroValue implements Builder.InsertZeroValue. func (b *builder) InsertZeroValue(t Type) { if b.zeros[t].Valid() { @@ -256,7 +283,7 @@ func (b *builder) Init(s *Signature) { sig.used = false } - b.ints = b.ints[:0] + b.redundantParams = b.redundantParams[:0] b.blkStack = b.blkStack[:0] b.blkStack2 = b.blkStack2[:0] b.dominators = b.dominators[:0] @@ -265,17 +292,11 @@ func (b *builder) Init(s *Signature) { for v := ValueID(0); v < b.nextValueID; v++ { delete(b.valueAnnotations, v) - delete(b.valueIDAliases, v) - b.valueRefCounts[v] = 0 - b.valueIDToInstruction[v] = nil + b.valuesInfo[v] = ValueInfo{alias: ValueInvalid} } b.nextValueID = 0 b.reversePostOrderedBasicBlocks = b.reversePostOrderedBasicBlocks[:0] b.doneBlockLayout = false - for i := range b.valueRefCounts { - b.valueRefCounts[i] = 0 - } - b.currentSourceOffset = sourceOffsetUnknown } @@ -355,7 +376,7 @@ func (b *builder) Idom(blk BasicBlock) BasicBlock { // InsertInstruction implements Builder.InsertInstruction. func (b *builder) InsertInstruction(instr *Instruction) { - b.currentBB.InsertInstruction(instr) + b.currentBB.insertInstruction(b, instr) if l := b.currentSourceOffset; l.Valid() { // Emit the source offset info only when the instruction has side effect because @@ -377,7 +398,7 @@ func (b *builder) InsertInstruction(instr *Instruction) { } r1 := b.allocateValue(t1) - instr.rValue = r1 + instr.rValue = r1.setInstructionID(instr.id) tsl := len(ts) if tsl == 0 { @@ -386,20 +407,14 @@ func (b *builder) InsertInstruction(instr *Instruction) { rValues := b.varLengthPool.Allocate(tsl) for i := 0; i < tsl; i++ { - rValues = rValues.Append(&b.varLengthPool, b.allocateValue(ts[i])) + rn := b.allocateValue(ts[i]) + rValues = rValues.Append(&b.varLengthPool, rn.setInstructionID(instr.id)) } instr.rValues = rValues } // DefineVariable implements Builder.DefineVariable. func (b *builder) DefineVariable(variable Variable, value Value, block BasicBlock) { - if b.variables[variable].invalid() { - panic("BUG: trying to define variable " + variable.String() + " but is not declared yet") - } - - if b.variables[variable] != value.Type() { - panic(fmt.Sprintf("BUG: inconsistent type for variable %d: expected %s but got %s", variable, b.variables[variable], value.Type())) - } bb := block.(*basicBlock) bb.lastDefinitions[variable] = value } @@ -426,20 +441,9 @@ func (b *builder) EntryBlock() BasicBlock { // DeclareVariable implements Builder.DeclareVariable. func (b *builder) DeclareVariable(typ Type) Variable { - v := b.allocateVariable() - iv := int(v) - if l := len(b.variables); l <= iv { - b.variables = append(b.variables, make([]Type, 2*(l+1))...) - } - b.variables[v] = typ - return v -} - -// allocateVariable allocates a new variable. -func (b *builder) allocateVariable() (ret Variable) { - ret = b.nextVariable + v := b.nextVariable b.nextVariable++ - return + return v.setType(typ) } // allocateValue implements Builder.AllocateValue. @@ -475,8 +479,7 @@ func (b *builder) findValueInLinearPath(variable Variable, blk *basicBlock) Valu // MustFindValue implements Builder.MustFindValue. func (b *builder) MustFindValue(variable Variable) Value { - typ := b.definedVariableType(variable) - return b.findValue(typ, variable, b.currentBB) + return b.findValue(variable.getType(), variable, b.currentBB) } // findValue recursively tries to find the latest definition of a `variable`. The algorithm is described in @@ -504,7 +507,7 @@ func (b *builder) findValue(typ Type, variable Variable, blk *basicBlock) 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)] + return b.zeros[variable.getType()] } if pred := blk.singlePred; pred != nil { @@ -536,14 +539,13 @@ func (b *builder) findValue(typ Type, variable Variable, blk *basicBlock) Value 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) + blk.addParamOn(b, 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. @@ -566,8 +568,8 @@ func (b *builder) Seal(raw BasicBlock) { for _, v := range blk.unknownValues { variable, phiValue := v.variable, v.value - typ := b.definedVariableType(variable) - blk.addParamOn(phiValue) + typ := variable.getType() + blk.addParamOn(b, phiValue) for i := range blk.preds { pred := &blk.preds[i] predValue := b.findValue(typ, variable, pred.blk) @@ -579,15 +581,6 @@ func (b *builder) Seal(raw BasicBlock) { } } -// definedVariableType returns the type of the given variable. If the variable is not defined yet, it panics. -func (b *builder) definedVariableType(variable Variable) Type { - typ := b.variables[variable] - if typ.invalid() { - panic(fmt.Sprintf("%s is not defined yet", variable)) - } - return typ -} - // Format implements Builder.Format. func (b *builder) Format() string { str := strings.Builder{} @@ -689,15 +682,24 @@ func (b *builder) blockIteratorReversePostOrderNext() *basicBlock { } } -// ValueRefCounts implements Builder.ValueRefCounts. -func (b *builder) ValueRefCounts() []int { - return b.valueRefCounts +// ValuesInfo implements Builder.ValuesInfo. +func (b *builder) ValuesInfo() []ValueInfo { + return b.valuesInfo } // alias records the alias of the given values. The alias(es) will be // eliminated in the optimization pass via resolveArgumentAlias. func (b *builder) alias(dst, src Value) { - b.valueIDAliases[dst.ID()] = src + did := int(dst.ID()) + if did >= len(b.valuesInfo) { + l := did + 1 - len(b.valuesInfo) + b.valuesInfo = append(b.valuesInfo, make([]ValueInfo, l)...) + view := b.valuesInfo[len(b.valuesInfo)-l:] + for i := range view { + view[i].alias = ValueInvalid + } + } + b.valuesInfo[did].alias = src } // resolveArgumentAlias resolves the alias of the arguments of the given instruction. @@ -722,10 +724,13 @@ func (b *builder) resolveArgumentAlias(instr *Instruction) { // resolveAlias resolves the alias of the given value. func (b *builder) resolveAlias(v Value) Value { + info := b.valuesInfo + l := ValueID(len(info)) // Some aliases are chained, so we need to resolve them recursively. for { - if src, ok := b.valueIDAliases[v.ID()]; ok { - v = src + vid := v.ID() + if vid < l && info[vid].alias.Valid() { + v = info[vid].alias } else { break } @@ -773,3 +778,13 @@ func (b *builder) LoopNestingForestRoots() []BasicBlock { func (b *builder) LowestCommonAncestor(blk1, blk2 BasicBlock) BasicBlock { return b.sparseTree.findLCA(blk1.ID(), blk2.ID()) } + +// InstructionOfValue returns the instruction that produces the given Value, or nil +// if the Value is not produced by any instruction. +func (b *builder) InstructionOfValue(v Value) *Instruction { + instrID := v.instructionID() + if instrID <= 0 { + return nil + } + return b.instructionsPool.View(instrID - 1) +} diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/instructions.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/instructions.go index 3e3482efc..9a3d1da6e 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/instructions.go +++ b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/instructions.go @@ -25,11 +25,13 @@ type Instruction struct { v3 Value vs Values typ Type - blk BasicBlock - targets []BasicBlock prev, next *Instruction - rValue Value + // rValue is the (first) return value of this instruction. + // For branching instructions except for OpcodeBrTable, they hold BlockID to jump cast to Value. + rValue Value + // rValues are the rest of the return values of this instruction. + // For OpcodeBrTable, it holds the list of BlockID to jump cast to Value. rValues Values gid InstructionGroupID sourceOffset SourceOffset @@ -105,6 +107,9 @@ type InstructionGroupID uint32 // Returns Value(s) produced by this instruction if any. // The `first` is the first return value, and `rest` is the rest of the values. func (i *Instruction) Returns() (first Value, rest []Value) { + if i.IsBranching() { + return ValueInvalid, nil + } return i.rValue, i.rValues.View() } @@ -2077,7 +2082,7 @@ func (i *Instruction) InvertBrx() { } // BranchData returns the branch data for this instruction necessary for backends. -func (i *Instruction) BranchData() (condVal Value, blockArgs []Value, target BasicBlock) { +func (i *Instruction) BranchData() (condVal Value, blockArgs []Value, target BasicBlockID) { switch i.opcode { case OpcodeJump: condVal = ValueInvalid @@ -2087,17 +2092,17 @@ func (i *Instruction) BranchData() (condVal Value, blockArgs []Value, target Bas panic("BUG") } blockArgs = i.vs.View() - target = i.blk + target = BasicBlockID(i.rValue) return } // BrTableData returns the branch table data for this instruction necessary for backends. -func (i *Instruction) BrTableData() (index Value, targets []BasicBlock) { +func (i *Instruction) BrTableData() (index Value, targets Values) { if i.opcode != OpcodeBrTable { panic("BUG: BrTableData only available for OpcodeBrTable") } index = i.v - targets = i.targets + targets = i.rValues return } @@ -2105,7 +2110,7 @@ func (i *Instruction) BrTableData() (index Value, targets []BasicBlock) { func (i *Instruction) AsJump(vs Values, target BasicBlock) *Instruction { i.opcode = OpcodeJump i.vs = vs - i.blk = target + i.rValue = Value(target.ID()) return i } @@ -2130,7 +2135,7 @@ func (i *Instruction) AsBrz(v Value, args Values, target BasicBlock) { i.opcode = OpcodeBrz i.v = v i.vs = args - i.blk = target + i.rValue = Value(target.ID()) } // AsBrnz initializes this instruction as a branch-if-not-zero instruction with OpcodeBrnz. @@ -2138,15 +2143,16 @@ func (i *Instruction) AsBrnz(v Value, args Values, target BasicBlock) *Instructi i.opcode = OpcodeBrnz i.v = v i.vs = args - i.blk = target + i.rValue = Value(target.ID()) return i } // AsBrTable initializes this instruction as a branch-table instruction with OpcodeBrTable. -func (i *Instruction) AsBrTable(index Value, targets []BasicBlock) { +// targets is a list of basic block IDs cast to Values. +func (i *Instruction) AsBrTable(index Value, targets Values) { i.opcode = OpcodeBrTable i.v = index - i.targets = targets + i.rValues = targets } // AsCall initializes this instruction as a call instruction with OpcodeCall. @@ -2531,7 +2537,8 @@ func (i *Instruction) Format(b Builder) string { if i.IsFallthroughJump() { vs[0] = " fallthrough" } else { - vs[0] = " " + i.blk.(*basicBlock).Name() + blockId := BasicBlockID(i.rValue) + vs[0] = " " + b.BasicBlock(blockId).Name() } for idx := range view { vs[idx+1] = view[idx].Format(b) @@ -2542,7 +2549,8 @@ func (i *Instruction) Format(b Builder) string { view := i.vs.View() vs := make([]string, len(view)+2) vs[0] = " " + i.v.Format(b) - vs[1] = i.blk.(*basicBlock).Name() + blockId := BasicBlockID(i.rValue) + vs[1] = b.BasicBlock(blockId).Name() for idx := range view { vs[idx+2] = view[idx].Format(b) } @@ -2551,8 +2559,8 @@ func (i *Instruction) Format(b Builder) string { // `BrTable index, [label1, label2, ... labelN]` instSuffix = fmt.Sprintf(" %s", i.v.Format(b)) instSuffix += ", [" - for i, target := range i.targets { - blk := target.(*basicBlock) + for i, target := range i.rValues.View() { + blk := b.BasicBlock(BasicBlockID(target)) if i == 0 { instSuffix += blk.Name() } else { @@ -2621,11 +2629,12 @@ func (i *Instruction) Format(b Builder) string { instr := i.opcode.String() + instSuffix var rvs []string - if rv := i.rValue; rv.Valid() { - rvs = append(rvs, rv.formatWithType(b)) + r1, rs := i.Returns() + if r1.Valid() { + rvs = append(rvs, r1.formatWithType(b)) } - for _, v := range i.rValues.View() { + for _, v := range rs { rvs = append(rvs, v.formatWithType(b)) } 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 89ec34b7e..b9763791d 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 @@ -112,7 +112,7 @@ func passDeadBlockEliminationOpt(b *builder) { // 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. + redundantParams := b.redundantParams[:0] // reuse the slice from previous iterations. // TODO: this might be costly for large programs, but at least, as far as I did the experiment, it's almost the // same as the single iteration version in terms of the overall compilation time. That *might be* mostly thanks to the fact @@ -128,10 +128,11 @@ func passRedundantPhiEliminationOpt(b *builder) { _ = 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.blockIteratorReversePostOrderNext(); blk != nil; blk = b.blockIteratorReversePostOrderNext() { - paramNum := len(blk.params) + params := blk.params.View() + paramNum := len(params) for paramIndex := 0; paramIndex < paramNum; paramIndex++ { - phiValue := blk.params[paramIndex] + phiValue := params[paramIndex] redundant := true nonSelfReferencingValue := ValueInvalid @@ -162,55 +163,58 @@ func passRedundantPhiEliminationOpt(b *builder) { } if redundant { - b.redundantParameterIndexToValue[paramIndex] = nonSelfReferencingValue - redundantParameterIndexes = append(redundantParameterIndexes, paramIndex) + redundantParams = append(redundantParams, redundantParam{ + index: paramIndex, uniqueValue: nonSelfReferencingValue, + }) } } - if len(b.redundantParameterIndexToValue) == 0 { + if len(redundantParams) == 0 { continue } changed = true // Remove the redundant PHIs from the argument list of branching instructions. for predIndex := range blk.preds { - var cur int + redundantParamsCur, predParamCur := 0, 0 predBlk := blk.preds[predIndex] branchInst := predBlk.branch view := branchInst.vs.View() for argIndex, value := range view { - if _, ok := b.redundantParameterIndexToValue[argIndex]; !ok { - view[cur] = value - cur++ + if len(redundantParams) == redundantParamsCur || + redundantParams[redundantParamsCur].index != argIndex { + view[predParamCur] = value + predParamCur++ + } else { + redundantParamsCur++ } } - branchInst.vs.Cut(cur) + branchInst.vs.Cut(predParamCur) } // Still need to have the definition of the value of the PHI (previously as the parameter). - for _, redundantParamIndex := range redundantParameterIndexes { - phiValue := blk.params[redundantParamIndex] - onlyValue := b.redundantParameterIndexToValue[redundantParamIndex] + for i := range redundantParams { + redundantValue := &redundantParams[i] + phiValue := params[redundantValue.index] // Create an alias in this block from the only phi argument to the phi value. - b.alias(phiValue, onlyValue) + b.alias(phiValue, redundantValue.uniqueValue) } // Finally, Remove the param from the blk. - var cur int + paramsCur, redundantParamsCur := 0, 0 for paramIndex := 0; paramIndex < paramNum; paramIndex++ { - param := blk.params[paramIndex] - if _, ok := b.redundantParameterIndexToValue[paramIndex]; !ok { - blk.params[cur] = param - cur++ + param := params[paramIndex] + if len(redundantParams) == redundantParamsCur || redundantParams[redundantParamsCur].index != paramIndex { + params[paramsCur] = param + paramsCur++ + } else { + redundantParamsCur++ } } - blk.params = blk.params[:cur] + blk.params.Cut(paramsCur) // Clears the map for the next iteration. - for _, paramIndex := range redundantParameterIndexes { - delete(b.redundantParameterIndexToValue, paramIndex) - } - redundantParameterIndexes = redundantParameterIndexes[:0] + redundantParams = redundantParams[:0] } if !changed { @@ -219,7 +223,7 @@ func passRedundantPhiEliminationOpt(b *builder) { } // Reuse the slice for the future passes. - b.ints = redundantParameterIndexes + b.redundantParams = redundantParams } // passDeadCodeEliminationOpt traverses all the instructions, and calculates the reference count of each Value, and @@ -231,11 +235,13 @@ func passRedundantPhiEliminationOpt(b *builder) { // TODO: the algorithm here might not be efficient. Get back to this later. func passDeadCodeEliminationOpt(b *builder) { nvid := int(b.nextValueID) - if nvid >= len(b.valueRefCounts) { - b.valueRefCounts = append(b.valueRefCounts, make([]int, nvid-len(b.valueRefCounts)+1)...) - } - if nvid >= len(b.valueIDToInstruction) { - b.valueIDToInstruction = append(b.valueIDToInstruction, make([]*Instruction, nvid-len(b.valueIDToInstruction)+1)...) + if nvid >= len(b.valuesInfo) { + l := nvid - len(b.valuesInfo) + 1 + b.valuesInfo = append(b.valuesInfo, make([]ValueInfo, l)...) + view := b.valuesInfo[len(b.valuesInfo)-l:] + for i := range view { + view[i].alias = ValueInvalid + } } // First, we gather all the instructions with side effects. @@ -255,14 +261,6 @@ func passDeadCodeEliminationOpt(b *builder) { // The strict side effect should create different instruction groups. gid++ } - - r1, rs := cur.Returns() - if r1.Valid() { - b.valueIDToInstruction[r1.ID()] = cur - } - for _, r := range rs { - b.valueIDToInstruction[r.ID()] = cur - } } } @@ -283,28 +281,28 @@ func passDeadCodeEliminationOpt(b *builder) { v1, v2, v3, vs := live.Args() if v1.Valid() { - producingInst := b.valueIDToInstruction[v1.ID()] + producingInst := b.InstructionOfValue(v1) if producingInst != nil { liveInstructions = append(liveInstructions, producingInst) } } if v2.Valid() { - producingInst := b.valueIDToInstruction[v2.ID()] + producingInst := b.InstructionOfValue(v2) if producingInst != nil { liveInstructions = append(liveInstructions, producingInst) } } if v3.Valid() { - producingInst := b.valueIDToInstruction[v3.ID()] + producingInst := b.InstructionOfValue(v3) if producingInst != nil { liveInstructions = append(liveInstructions, producingInst) } } for _, v := range vs { - producingInst := b.valueIDToInstruction[v.ID()] + producingInst := b.InstructionOfValue(v) if producingInst != nil { liveInstructions = append(liveInstructions, producingInst) } @@ -352,34 +350,19 @@ func (b *builder) incRefCount(id ValueID, from *Instruction) { if wazevoapi.SSALoggingEnabled { fmt.Printf("v%d referenced from %v\n", id, from.Format(b)) } - b.valueRefCounts[id]++ + info := &b.valuesInfo[id] + info.RefCount++ } // 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, int(b.nextValueID)-len(b.valueIDToInstruction)+1)...) - } - - for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() { - for cur := blk.rootInstr; cur != nil; cur = cur.next { - r1, rs := cur.Returns() - if r1.Valid() { - b.valueIDToInstruction[r1.ID()] = cur - } - for _, r := range rs { - b.valueIDToInstruction[r.ID()] = cur - } - } - } - for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() { for cur := blk.rootInstr; cur != nil; cur = cur.next { switch cur.Opcode() { // TODO: add more logics here. case OpcodeIshl, OpcodeSshr, OpcodeUshr: x, amount := cur.Arg2() - definingInst := b.valueIDToInstruction[amount.ID()] + definingInst := b.InstructionOfValue(amount) if definingInst == nil { // If there's no defining instruction, that means the amount is coming from the parameter. continue 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 584b5eade..0118e8b2e 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 @@ -33,7 +33,7 @@ func passLayoutBlocks(b *builder) { } nonSplitBlocks = append(nonSplitBlocks, blk) if i != len(b.reversePostOrderedBasicBlocks)-1 { - _ = maybeInvertBranches(blk, b.reversePostOrderedBasicBlocks[i+1]) + _ = maybeInvertBranches(b, blk, b.reversePostOrderedBasicBlocks[i+1]) } } @@ -111,7 +111,7 @@ func passLayoutBlocks(b *builder) { } fallthroughBranch := blk.currentInstr - if fallthroughBranch.opcode == OpcodeJump && fallthroughBranch.blk == trampoline { + if fallthroughBranch.opcode == OpcodeJump && BasicBlockID(fallthroughBranch.rValue) == trampoline.id { // This can be lowered as fallthrough at the end of the block. b.reversePostOrderedBasicBlocks = append(b.reversePostOrderedBasicBlocks, trampoline) trampoline.visited = 1 // mark as inserted. @@ -157,7 +157,7 @@ func (b *builder) markFallthroughJumps() { for i, blk := range b.reversePostOrderedBasicBlocks { if i < l { cur := blk.currentInstr - if cur.opcode == OpcodeJump && cur.blk == b.reversePostOrderedBasicBlocks[i+1] { + if cur.opcode == OpcodeJump && BasicBlockID(cur.rValue) == b.reversePostOrderedBasicBlocks[i+1].id { cur.AsFallthroughJump() } } @@ -168,7 +168,7 @@ func (b *builder) markFallthroughJumps() { // nextInRPO is the next block in the reverse post-order. // // Returns true if the branch is inverted for testing purpose. -func maybeInvertBranches(now *basicBlock, nextInRPO *basicBlock) bool { +func maybeInvertBranches(b *builder, now *basicBlock, nextInRPO *basicBlock) bool { fallthroughBranch := now.currentInstr if fallthroughBranch.opcode == OpcodeBrTable { return false @@ -187,7 +187,8 @@ func maybeInvertBranches(now *basicBlock, nextInRPO *basicBlock) bool { // So this block has two branches (a conditional branch followed by an unconditional branch) at the end. // We can invert the condition of the branch if it makes the fallthrough more likely. - fallthroughTarget, condTarget := fallthroughBranch.blk.(*basicBlock), condBranch.blk.(*basicBlock) + fallthroughTarget := b.basicBlock(BasicBlockID(fallthroughBranch.rValue)) + condTarget := b.basicBlock(BasicBlockID(condBranch.rValue)) if fallthroughTarget.loopHeader { // First, if the tail's target is loopHeader, we don't need to do anything here, @@ -231,8 +232,8 @@ invert: } condBranch.InvertBrx() - condBranch.blk = fallthroughTarget - fallthroughBranch.blk = condTarget + condBranch.rValue = Value(fallthroughTarget.ID()) + fallthroughBranch.rValue = Value(condTarget.ID()) if wazevoapi.SSALoggingEnabled { fmt.Printf("inverting branches at %d->%d and %d->%d\n", now.ID(), fallthroughTarget.ID(), now.ID(), condTarget.ID()) @@ -275,7 +276,7 @@ func (b *builder) splitCriticalEdge(pred, succ *basicBlock, predInfo *basicBlock // Replace originalBranch with the newBranch. newBranch := b.AllocateInstruction() newBranch.opcode = originalBranch.opcode - newBranch.blk = trampoline + newBranch.rValue = Value(trampoline.ID()) switch originalBranch.opcode { case OpcodeJump: case OpcodeBrz, OpcodeBrnz: @@ -303,7 +304,7 @@ func (b *builder) splitCriticalEdge(pred, succ *basicBlock, predInfo *basicBlock trampoline.validate(b) } - if len(trampoline.params) > 0 { + if len(trampoline.params.View()) > 0 { panic("trampoline should not have params") } diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/vs.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/vs.go index bcf83cbf8..d906e7e35 100644 --- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/vs.go +++ b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/vs.go @@ -15,17 +15,31 @@ import ( // // Variable is useful to track the SSA Values of a variable in the source program, and // can be used to find the corresponding latest SSA Value via Builder.FindValue. +// +// Higher 4-bit is used to store Type for this variable. type Variable uint32 // String implements fmt.Stringer. func (v Variable) String() string { - return fmt.Sprintf("var%d", v) + return fmt.Sprintf("var%d", v&0x0fffffff) +} + +func (v Variable) setType(typ Type) Variable { + if v >= 1<<28 { + panic(fmt.Sprintf("Too large variable: %d", v)) + } + return Variable(typ)<<28 | v +} + +func (v Variable) getType() Type { + return Type(v >> 28) } // Value represents an SSA value with a type information. The relationship with Variable is 1: N (including 0), // that means there might be multiple Variable(s) for a Value. // -// Higher 32-bit is used to store Type for this value. +// 32 to 59-bit is used to store the unique identifier of the Instruction that generates this value if any. +// 60 to 63-bit is used to store Type for this value. type Value uint64 // ValueID is the lower 32bit of Value, which is the pure identifier of Value without type info. @@ -33,7 +47,7 @@ type ValueID uint32 const ( valueIDInvalid ValueID = math.MaxUint32 - ValueInvalid Value = Value(valueIDInvalid) + ValueInvalid = Value(valueIDInvalid) ) // Format creates a debug string for this Value using the data stored in Builder. @@ -54,7 +68,7 @@ func (v Value) formatWithType(b Builder) (ret string) { if wazevoapi.SSALoggingEnabled { // This is useful to check live value analysis bugs. if bd := b.(*builder); bd.donePostBlockLayoutPasses { id := v.ID() - ret += fmt.Sprintf("(ref=%d)", bd.valueRefCounts[id]) + ret += fmt.Sprintf("(ref=%d)", bd.valuesInfo[id].RefCount) } } return ret @@ -67,7 +81,7 @@ func (v Value) Valid() bool { // Type returns the Type of this value. func (v Value) Type() Type { - return Type(v >> 32) + return Type(v >> 60) } // ID returns the valueID of this value. @@ -77,7 +91,20 @@ func (v Value) ID() ValueID { // setType sets a type to this Value and returns the updated Value. func (v Value) setType(typ Type) Value { - return v | Value(typ)<<32 + return v | Value(typ)<<60 +} + +// setInstructionID sets an Instruction.id to this Value and returns the updated Value. +func (v Value) setInstructionID(id int) Value { + if id < 0 || uint(id) >= 1<<28 { + panic(fmt.Sprintf("Too large instruction ID: %d", id)) + } + return v | Value(id)<<32 +} + +// instructionID() returns the Instruction.id of this Value. +func (v Value) instructionID() int { + return int(v>>32) & 0x0fffffff } // Values is a slice of Value. Use this instead of []Value to reuse the underlying memory. |