summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2024-08-15 00:08:55 +0000
committerLibravatar GitHub <noreply@github.com>2024-08-15 00:08:55 +0000
commit09f24e044653b1327ac1c40f3ab150e3f0184f23 (patch)
tree1d9984d053fa5c8d1203abaa49b8752a1532ff11 /vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa
parentupdate go-fastcopy to v1.1.3 (#3200) (diff)
downloadgotosocial-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')
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block.go43
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort.go2
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort_old.go24
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/builder.go169
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/instructions.go47
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass.go105
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_blk_layouts.go19
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/vs.go39
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.