summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa
diff options
context:
space:
mode:
authorLibravatar Terin Stock <terinjokes@gmail.com>2025-03-09 17:47:56 +0100
committerLibravatar Terin Stock <terinjokes@gmail.com>2025-03-10 01:59:49 +0100
commit3ac1ee16f377d31a0fb80c8dae28b6239ac4229e (patch)
treef61faa581feaaeaba2542b9f2b8234a590684413 /vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa
parent[chore] update URLs to forked source (diff)
downloadgotosocial-3ac1ee16f377d31a0fb80c8dae28b6239ac4229e.tar.xz
[chore] remove vendor
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.go379
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort.go32
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/builder.go790
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/cmp.go107
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/funcref.go12
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/instructions.go2976
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass.go393
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_blk_layouts.go334
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_cfg.go313
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/signature.go49
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/ssa.go14
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/type.go115
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/vs.go114
13 files changed, 0 insertions, 5628 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
deleted file mode 100644
index cf7f14d3b..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block.go
+++ /dev/null
@@ -1,379 +0,0 @@
-package ssa
-
-import (
- "fmt"
- "strconv"
- "strings"
-
- "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
-)
-
-// BasicBlock represents the Basic Block of an SSA function.
-// Each BasicBlock always ends with branching instructions (e.g. Branch, Return, etc.),
-// and at most two branches are allowed. If there's two branches, these two are placed together at the end of the block.
-// In other words, there's no branching instruction in the middle of the block.
-//
-// Note: we use the "block argument" variant of SSA, instead of PHI functions. See the package level doc comments.
-//
-// Note: we use "parameter/param" as a placeholder which represents a variant of PHI, and "argument/arg" as an actual
-// Value passed to that "parameter/param".
-type BasicBlock interface {
- // ID returns the unique ID of this block.
- ID() BasicBlockID
-
- // Name returns the unique string ID of this block. e.g. blk0, blk1, ...
- Name() string
-
- // AddParam adds the parameter to the block whose type specified by `t`.
- AddParam(b Builder, t Type) Value
-
- // Params returns the number of parameters to this block.
- Params() int
-
- // Param returns (Variable, Value) which corresponds to the i-th parameter of this block.
- // The returned Value is the definition of the param in this block.
- Param(i int) Value
-
- // Root returns the root instruction of this block.
- Root() *Instruction
-
- // Tail returns the tail instruction of this block.
- Tail() *Instruction
-
- // EntryBlock returns true if this block represents the function entry.
- EntryBlock() bool
-
- // ReturnBlock returns ture if this block represents the function return.
- ReturnBlock() bool
-
- // 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
-
- // Preds returns the number of predecessors of this block.
- Preds() int
-
- // Pred returns the i-th predecessor of this block.
- Pred(i int) BasicBlock
-
- // Succs returns the number of successors of this block.
- Succs() int
-
- // Succ returns the i-th successor of this block.
- Succ(i int) BasicBlock
-
- // LoopHeader returns true if this block is a loop header.
- LoopHeader() bool
-
- // LoopNestingForestChildren returns the children of this block in the loop nesting forest.
- LoopNestingForestChildren() []BasicBlock
-}
-
-type (
- // basicBlock is a basic block in a SSA-transformed function.
- basicBlock struct {
- id BasicBlockID
- 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 Values
- 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.
- lastDefinitions map[Variable]Value
- // unknownsValues are used in builder.findValue. The usage is well-described in the paper.
- unknownValues []unknownValue
- // invalid is true if this block is made invalid during optimizations.
- invalid bool
- // sealed is true if this is sealed (all the predecessors are known).
- sealed bool
- // loopHeader is true if this block is a loop header:
- //
- // > A loop header (sometimes called the entry point of the loop) is a dominator that is the target
- // > of a loop-forming back edge. The loop header dominates all blocks in the loop body.
- // > A block may be a loop header for more than one loop. A loop may have multiple entry points,
- // > in which case it has no "loop header".
- //
- // See https://en.wikipedia.org/wiki/Control-flow_graph for more details.
- //
- // This is modified during the subPassLoopDetection pass.
- loopHeader bool
-
- // 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 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 int32
-
- // visited is used during various traversals.
- visited int32
-
- // child and sibling are the ones in the dominator tree.
- child, sibling *basicBlock
- }
- // BasicBlockID is the unique ID of a basicBlock.
- BasicBlockID uint32
-
- unknownValue struct {
- // variable is the variable that this unknownValue represents.
- variable Variable
- // value is the value that this unknownValue represents.
- value Value
- }
-)
-
-// basicBlockVarLengthNil is the default nil value for basicBlock.loopNestingForestChildren.
-var basicBlockVarLengthNil = wazevoapi.NewNilVarLength[BasicBlock]()
-
-const basicBlockIDReturnBlock = 0xffffffff
-
-// Name implements BasicBlock.Name.
-func (bb *basicBlock) Name() string {
- if bb.id == basicBlockIDReturnBlock {
- return "blk_ret"
- } else {
- return fmt.Sprintf("blk%d", bb.id)
- }
-}
-
-// String implements fmt.Stringer for debugging.
-func (bid BasicBlockID) String() string {
- if bid == basicBlockIDReturnBlock {
- return "blk_ret"
- } else {
- return fmt.Sprintf("blk%d", bid)
- }
-}
-
-// ID implements BasicBlock.ID.
-func (bb *basicBlock) ID() BasicBlockID {
- return bb.id
-}
-
-// basicBlockPredecessorInfo is the information of a predecessor of a basicBlock.
-// predecessor is determined by a pair of block and the branch instruction used to jump to the successor.
-type basicBlockPredecessorInfo struct {
- blk *basicBlock
- branch *Instruction
-}
-
-// EntryBlock implements BasicBlock.EntryBlock.
-func (bb *basicBlock) EntryBlock() bool {
- return bb.id == 0
-}
-
-// ReturnBlock implements BasicBlock.ReturnBlock.
-func (bb *basicBlock) ReturnBlock() bool {
- return bb.id == basicBlockIDReturnBlock
-}
-
-// AddParam implements BasicBlock.AddParam.
-func (bb *basicBlock) AddParam(b Builder, typ Type) Value {
- paramValue := b.allocateValue(typ)
- 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(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.View())
-}
-
-// Param implements BasicBlock.Param.
-func (bb *basicBlock) Param(i int) Value {
- return bb.params.View()[i]
-}
-
-// Valid implements BasicBlock.Valid.
-func (bb *basicBlock) Valid() bool {
- return !bb.invalid
-}
-
-// Sealed implements BasicBlock.Sealed.
-func (bb *basicBlock) Sealed() bool {
- return bb.sealed
-}
-
-// insertInstruction implements BasicBlock.InsertInstruction.
-func (bb *basicBlock) insertInstruction(b *builder, next *Instruction) {
- current := bb.currentInstr
- if current != nil {
- current.next = next
- next.prev = current
- } else {
- bb.rootInstr = next
- }
- bb.currentInstr = next
-
- switch next.opcode {
- case OpcodeJump, OpcodeBrz, OpcodeBrnz:
- target := BasicBlockID(next.rValue)
- b.basicBlock(target).addPred(bb, next)
- case OpcodeBrTable:
- for _, _target := range next.rValues.View() {
- target := BasicBlockID(_target)
- b.basicBlock(target).addPred(bb, next)
- }
- }
-}
-
-// NumPreds implements BasicBlock.NumPreds.
-func (bb *basicBlock) NumPreds() int {
- return len(bb.preds)
-}
-
-// Preds implements BasicBlock.Preds.
-func (bb *basicBlock) Preds() int {
- return len(bb.preds)
-}
-
-// Pred implements BasicBlock.Pred.
-func (bb *basicBlock) Pred(i int) BasicBlock {
- return bb.preds[i].blk
-}
-
-// Succs implements BasicBlock.Succs.
-func (bb *basicBlock) Succs() int {
- return len(bb.success)
-}
-
-// Succ implements BasicBlock.Succ.
-func (bb *basicBlock) Succ(i int) BasicBlock {
- return bb.success[i]
-}
-
-// Root implements BasicBlock.Root.
-func (bb *basicBlock) Root() *Instruction {
- return bb.rootInstr
-}
-
-// Tail implements BasicBlock.Tail.
-func (bb *basicBlock) Tail() *Instruction {
- return bb.currentInstr
-}
-
-// reset resets the basicBlock to its initial state so that it can be reused for another function.
-func resetBasicBlock(bb *basicBlock) {
- bb.params = ValuesNil
- bb.rootInstr, bb.currentInstr = nil, nil
- bb.preds = bb.preds[:0]
- bb.success = bb.success[:0]
- bb.invalid, bb.sealed = false, false
- bb.singlePred = nil
- bb.unknownValues = bb.unknownValues[:0]
- bb.lastDefinitions = wazevoapi.ResetMap(bb.lastDefinitions)
- bb.reversePostOrder = -1
- bb.visited = 0
- bb.loopNestingForestChildren = basicBlockVarLengthNil
- bb.loopHeader = false
- bb.sibling = nil
- bb.child = nil
-}
-
-// addPred adds a predecessor to this block specified by the branch instruction.
-func (bb *basicBlock) addPred(blk BasicBlock, branch *Instruction) {
- if bb.sealed {
- panic("BUG: trying to add predecessor to a sealed block: " + bb.Name())
- }
-
- pred := blk.(*basicBlock)
- for i := range bb.preds {
- existingPred := &bb.preds[i]
- if existingPred.blk == pred && existingPred.branch != branch {
- // If the target is already added, then this must come from the same BrTable,
- // otherwise such redundant branch should be eliminated by the frontend. (which should be simpler).
- panic(fmt.Sprintf("BUG: redundant non BrTable jumps in %s whose targes are the same", bb.Name()))
- }
- }
-
- bb.preds = append(bb.preds, basicBlockPredecessorInfo{
- blk: pred,
- branch: branch,
- })
-
- pred.success = append(pred.success, bb)
-}
-
-// formatHeader returns the string representation of the header of the basicBlock.
-func (bb *basicBlock) formatHeader(b Builder) string {
- ps := make([]string, len(bb.params.View()))
- for i, p := range bb.params.View() {
- ps[i] = p.formatWithType(b)
- }
-
- if len(bb.preds) > 0 {
- preds := make([]string, 0, len(bb.preds))
- for _, pred := range bb.preds {
- if pred.blk.invalid {
- continue
- }
- preds = append(preds, fmt.Sprintf("blk%d", pred.blk.id))
-
- }
- return fmt.Sprintf("blk%d: (%s) <-- (%s)",
- bb.id, strings.Join(ps, ","), strings.Join(preds, ","))
- } else {
- return fmt.Sprintf("blk%d: (%s)", bb.id, strings.Join(ps, ", "))
- }
-}
-
-// validates validates the basicBlock for debugging purpose.
-func (bb *basicBlock) validate(b *builder) {
- if bb.invalid {
- panic("BUG: trying to validate an invalid block: " + bb.Name())
- }
- if len(bb.preds) > 0 {
- for _, pred := range bb.preds {
- if pred.branch.opcode != OpcodeBrTable {
- 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()))
- }
- }
-
- var exp int
- if bb.ReturnBlock() {
- exp = len(b.currentSignature.Results)
- } else {
- 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.View()), pred.branch.Format(b),
- ))
- }
-
- }
- }
-}
-
-// String implements fmt.Stringer for debugging purpose only.
-func (bb *basicBlock) String() string {
- return strconv.Itoa(int(bb.id))
-}
-
-// LoopNestingForestChildren implements BasicBlock.LoopNestingForestChildren.
-func (bb *basicBlock) LoopNestingForestChildren() []BasicBlock {
- return bb.loopNestingForestChildren.View()
-}
-
-// LoopHeader implements BasicBlock.LoopHeader.
-func (bb *basicBlock) LoopHeader() bool {
- return bb.loopHeader
-}
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
deleted file mode 100644
index fb98298f7..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/basic_block_sort.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package ssa
-
-import (
- "slices"
-)
-
-func sortBlocks(blocks []*basicBlock) {
- slices.SortFunc(blocks, func(i, j *basicBlock) int {
- jIsReturn := j.ReturnBlock()
- iIsReturn := i.ReturnBlock()
- if iIsReturn && jIsReturn {
- return 0
- }
- if jIsReturn {
- return 1
- }
- if iIsReturn {
- return -1
- }
- iRoot, jRoot := i.rootInstr, j.rootInstr
- if iRoot == nil && jRoot == nil { // For testing.
- return 0
- }
- if jRoot == nil {
- return 1
- }
- if iRoot == nil {
- return -1
- }
- return i.rootInstr.id - j.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
deleted file mode 100644
index 43dd7d292..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/builder.go
+++ /dev/null
@@ -1,790 +0,0 @@
-package ssa
-
-import (
- "fmt"
- "sort"
- "strings"
-
- "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
-)
-
-// Builder is used to builds SSA consisting of Basic Blocks per function.
-type Builder interface {
- // Init must be called to reuse this builder for the next function.
- Init(typ *Signature)
-
- // Signature returns the Signature of the currently-compiled function.
- Signature() *Signature
-
- // BlockIDMax returns the maximum value of BasicBlocksID existing in the currently-compiled function.
- BlockIDMax() BasicBlockID
-
- // AllocateBasicBlock creates a basic block in SSA function.
- AllocateBasicBlock() BasicBlock
-
- // CurrentBlock returns the currently handled BasicBlock which is set by the latest call to SetCurrentBlock.
- CurrentBlock() BasicBlock
-
- // EntryBlock returns the entry BasicBlock of the currently-compiled function.
- EntryBlock() BasicBlock
-
- // SetCurrentBlock sets the instruction insertion target to the BasicBlock `b`.
- SetCurrentBlock(b BasicBlock)
-
- // DeclareVariable declares a Variable of the given Type.
- DeclareVariable(Type) Variable
-
- // DefineVariable defines a variable in the `block` with value.
- // The defining instruction will be inserted into the `block`.
- DefineVariable(variable Variable, value Value, block BasicBlock)
-
- // DefineVariableInCurrentBB is the same as DefineVariable except the definition is
- // inserted into the current BasicBlock. Alias to DefineVariable(x, y, CurrentBlock()).
- DefineVariableInCurrentBB(variable Variable, value Value)
-
- // AllocateInstruction returns a new Instruction.
- AllocateInstruction() *Instruction
-
- // InsertInstruction executes BasicBlock.InsertInstruction for the currently handled basic block.
- InsertInstruction(raw *Instruction)
-
- // allocateValue allocates an unused Value.
- allocateValue(typ Type) Value
-
- // MustFindValue searches the latest definition of the given Variable and returns the result.
- MustFindValue(variable Variable) 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
-
- // Seal declares that we've known all the predecessors to this block and were added via AddPred.
- // After calling this, AddPred will be forbidden.
- Seal(blk BasicBlock)
-
- // AnnotateValue is for debugging purpose.
- AnnotateValue(value Value, annotation string)
-
- // DeclareSignature appends the *Signature to be referenced by various instructions (e.g. OpcodeCall).
- DeclareSignature(signature *Signature)
-
- // Signatures returns the slice of declared Signatures.
- Signatures() []*Signature
-
- // ResolveSignature returns the Signature which corresponds to SignatureID.
- ResolveSignature(id SignatureID) *Signature
-
- // RunPasses runs various passes on the constructed SSA function.
- RunPasses()
-
- // Format returns the debugging string of the SSA function.
- Format() string
-
- // BlockIteratorBegin initializes the state to iterate over all the valid BasicBlock(s) compiled.
- // Combined with BlockIteratorNext, we can use this like:
- //
- // for blk := builder.BlockIteratorBegin(); blk != nil; blk = builder.BlockIteratorNext() {
- // // ...
- // }
- //
- // The returned blocks are ordered in the order of AllocateBasicBlock being called.
- BlockIteratorBegin() BasicBlock
-
- // BlockIteratorNext advances the state for iteration initialized by BlockIteratorBegin.
- // Returns nil if there's no unseen BasicBlock.
- BlockIteratorNext() BasicBlock
-
- // 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.
- BlockIteratorReversePostOrderBegin() BasicBlock
-
- // BlockIteratorReversePostOrderNext is almost the same as BlockIteratorPostOrderNext except it returns the BasicBlock in the reverse post-order.
- // This is available after RunPasses is run.
- BlockIteratorReversePostOrderNext() BasicBlock
-
- // ReturnBlock returns the BasicBlock which is used to return from the function.
- ReturnBlock() BasicBlock
-
- // InsertUndefined inserts an undefined instruction at the current position.
- InsertUndefined()
-
- // SetCurrentSourceOffset sets the current source offset. The incoming instruction will be annotated with this offset.
- SetCurrentSourceOffset(line SourceOffset)
-
- // LoopNestingForestRoots returns the roots of the loop nesting forest.
- LoopNestingForestRoots() []BasicBlock
-
- // LowestCommonAncestor returns the lowest common ancestor in the dominator tree of the given BasicBlock(s).
- LowestCommonAncestor(blk1, blk2 BasicBlock) BasicBlock
-
- // 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)
-
- // 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),
- returnBlk: &basicBlock{id: basicBlockIDReturnBlock},
- }
-}
-
-// builder implements Builder interface.
-type builder struct {
- basicBlocksPool wazevoapi.Pool[basicBlock]
- instructionsPool wazevoapi.Pool[Instruction]
- varLengthPool wazevoapi.VarLengthPool[Value]
- signatures map[SignatureID]*Signature
- currentSignature *Signature
-
- // reversePostOrderedBasicBlocks are the BasicBlock(s) ordered in the reverse post-order after passCalculateImmediateDominators.
- reversePostOrderedBasicBlocks []*basicBlock
- currentBB *basicBlock
- returnBlk *basicBlock
-
- // nextValueID is used by builder.AllocateValue.
- nextValueID ValueID
- // nextVariable is used by builder.AllocateVariable.
- nextVariable Variable
-
- // valueAnnotations contains the annotations for each Value, only used for debugging.
- valueAnnotations map[ValueID]string
-
- // 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.
- 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
- blkStack []*basicBlock
- blkStack2 []*basicBlock
- redundantParams []redundantParam
-
- // blockIterCur is used to implement blockIteratorBegin and blockIteratorNext.
- blockIterCur int
-
- // donePreBlockLayoutPasses is true if all the passes before LayoutBlocks are called.
- donePreBlockLayoutPasses bool
- // doneBlockLayout is true if LayoutBlocks is called.
- doneBlockLayout bool
- // donePostBlockLayoutPasses is true if all the passes after LayoutBlocks are called.
- donePostBlockLayoutPasses bool
-
- currentSourceOffset SourceOffset
-
- // zeros are the zero value constants for each type.
- 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() {
- 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] {
- return &b.varLengthPool
-}
-
-// ReturnBlock implements Builder.ReturnBlock.
-func (b *builder) ReturnBlock() BasicBlock {
- return b.returnBlk
-}
-
-// Init implements Builder.Reset.
-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
- for _, sig := range b.signatures {
- sig.used = false
- }
-
- b.redundantParams = b.redundantParams[:0]
- b.blkStack = b.blkStack[:0]
- b.blkStack2 = b.blkStack2[:0]
- b.dominators = b.dominators[:0]
- b.loopNestingForestRoots = b.loopNestingForestRoots[:0]
- b.basicBlocksPool.Reset()
-
- for v := ValueID(0); v < b.nextValueID; v++ {
- delete(b.valueAnnotations, v)
- b.valuesInfo[v] = ValueInfo{alias: ValueInvalid}
- }
- b.nextValueID = 0
- b.reversePostOrderedBasicBlocks = b.reversePostOrderedBasicBlocks[:0]
- b.doneBlockLayout = false
- b.currentSourceOffset = sourceOffsetUnknown
-}
-
-// Signature implements Builder.Signature.
-func (b *builder) Signature() *Signature {
- return b.currentSignature
-}
-
-// AnnotateValue implements Builder.AnnotateValue.
-func (b *builder) AnnotateValue(value Value, a string) {
- b.valueAnnotations[value.ID()] = a
-}
-
-// AllocateInstruction implements Builder.AllocateInstruction.
-func (b *builder) AllocateInstruction() *Instruction {
- instr := b.instructionsPool.Allocate()
- instr.id = b.instructionsPool.Allocated()
- return instr
-}
-
-// DeclareSignature implements Builder.AnnotateValue.
-func (b *builder) DeclareSignature(s *Signature) {
- b.signatures[s.ID] = s
- s.used = false
-}
-
-// Signatures implements Builder.Signatures.
-func (b *builder) Signatures() (ret []*Signature) {
- for _, sig := range b.signatures {
- ret = append(ret, sig)
- }
- sort.Slice(ret, func(i, j int) bool {
- return ret[i].ID < ret[j].ID
- })
- return
-}
-
-// SetCurrentSourceOffset implements Builder.SetCurrentSourceOffset.
-func (b *builder) SetCurrentSourceOffset(l SourceOffset) {
- b.currentSourceOffset = l
-}
-
-func (b *builder) usedSignatures() (ret []*Signature) {
- for _, sig := range b.signatures {
- if sig.used {
- ret = append(ret, sig)
- }
- }
- sort.Slice(ret, func(i, j int) bool {
- return ret[i].ID < ret[j].ID
- })
- return
-}
-
-// ResolveSignature implements Builder.ResolveSignature.
-func (b *builder) ResolveSignature(id SignatureID) *Signature {
- return b.signatures[id]
-}
-
-// AllocateBasicBlock implements Builder.AllocateBasicBlock.
-func (b *builder) AllocateBasicBlock() BasicBlock {
- return b.allocateBasicBlock()
-}
-
-// allocateBasicBlock allocates a new basicBlock.
-func (b *builder) allocateBasicBlock() *basicBlock {
- id := BasicBlockID(b.basicBlocksPool.Allocated())
- blk := b.basicBlocksPool.Allocate()
- blk.id = id
- return blk
-}
-
-// Idom implements Builder.Idom.
-func (b *builder) Idom(blk BasicBlock) BasicBlock {
- return b.dominators[blk.ID()]
-}
-
-// InsertInstruction implements Builder.InsertInstruction.
-func (b *builder) InsertInstruction(instr *Instruction) {
- b.currentBB.insertInstruction(b, instr)
-
- if l := b.currentSourceOffset; l.Valid() {
- // Emit the source offset info only when the instruction has side effect because
- // these are the only instructions that are accessed by stack unwinding.
- // This reduces the significant amount of the offset info in the binary.
- if instr.sideEffect() != sideEffectNone {
- instr.annotateSourceOffset(l)
- }
- }
-
- resultTypesFn := instructionReturnTypes[instr.opcode]
- if resultTypesFn == nil {
- panic("TODO: " + instr.Format(b))
- }
-
- t1, ts := resultTypesFn(b, instr)
- if t1.invalid() {
- return
- }
-
- r1 := b.allocateValue(t1)
- instr.rValue = r1.setInstructionID(instr.id)
-
- tsl := len(ts)
- if tsl == 0 {
- return
- }
-
- rValues := b.varLengthPool.Allocate(tsl)
- for i := 0; i < tsl; 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) {
- bb := block.(*basicBlock)
- bb.lastDefinitions[variable] = value
-}
-
-// DefineVariableInCurrentBB implements Builder.DefineVariableInCurrentBB.
-func (b *builder) DefineVariableInCurrentBB(variable Variable, value Value) {
- b.DefineVariable(variable, value, b.currentBB)
-}
-
-// SetCurrentBlock implements Builder.SetCurrentBlock.
-func (b *builder) SetCurrentBlock(bb BasicBlock) {
- b.currentBB = bb.(*basicBlock)
-}
-
-// CurrentBlock implements Builder.CurrentBlock.
-func (b *builder) CurrentBlock() BasicBlock {
- return b.currentBB
-}
-
-// EntryBlock implements Builder.EntryBlock.
-func (b *builder) EntryBlock() BasicBlock {
- return b.entryBlk()
-}
-
-// DeclareVariable implements Builder.DeclareVariable.
-func (b *builder) DeclareVariable(typ Type) Variable {
- v := b.nextVariable
- b.nextVariable++
- return v.setType(typ)
-}
-
-// allocateValue implements Builder.AllocateValue.
-func (b *builder) allocateValue(typ Type) (v Value) {
- v = Value(b.nextValueID)
- v = v.setType(typ)
- b.nextValueID++
- return
-}
-
-// FindValueInLinearPath implements Builder.FindValueInLinearPath.
-func (b *builder) FindValueInLinearPath(variable Variable) Value {
- return b.findValueInLinearPath(variable, b.currentBB)
-}
-
-func (b *builder) findValueInLinearPath(variable Variable, blk *basicBlock) Value {
- if val, ok := blk.lastDefinitions[variable]; ok {
- return val
- } else if !blk.sealed {
- return ValueInvalid
- }
-
- if pred := blk.singlePred; pred != nil {
- // If this block is sealed and have only one predecessor,
- // we can use the value in that block without ambiguity on definition.
- return b.findValueInLinearPath(variable, pred)
- }
- if len(blk.preds) == 1 {
- panic("BUG")
- }
- return ValueInvalid
-}
-
-// MustFindValue implements Builder.MustFindValue.
-func (b *builder) MustFindValue(variable Variable) Value {
- return b.findValue(variable.getType(), variable, b.currentBB)
-}
-
-// findValue recursively tries to find the latest definition of a `variable`. The algorithm is described in
-// the section 2 of the paper https://link.springer.com/content/pdf/10.1007/978-3-642-37051-9_6.pdf.
-//
-// TODO: reimplement this in iterative, not recursive, to avoid stack overflow.
-func (b *builder) findValue(typ Type, variable Variable, blk *basicBlock) Value {
- if val, ok := blk.lastDefinitions[variable]; ok {
- // The value is already defined in this block!
- return val
- } else if !blk.sealed { // Incomplete CFG as in the paper.
- // If this is not sealed, that means it might have additional unknown predecessor later on.
- // So we temporarily define the placeholder value here (not add as a parameter yet!),
- // and record it as unknown.
- // The unknown values are resolved when we call seal this block via BasicBlock.Seal().
- value := b.allocateValue(typ)
- if wazevoapi.SSALoggingEnabled {
- fmt.Printf("adding unknown value placeholder for %s at %d\n", variable, blk.id)
- }
- blk.lastDefinitions[variable] = value
- blk.unknownValues = append(blk.unknownValues, unknownValue{
- variable: variable,
- 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[variable.getType()]
- }
-
- if pred := blk.singlePred; pred != nil {
- // If this block is sealed and have only one predecessor,
- // we can use the value in that block without ambiguity on definition.
- return b.findValue(typ, variable, pred)
- } else if len(blk.preds) == 0 {
- panic("BUG: value is not defined for " + variable.String())
- }
-
- // If this block has multiple predecessors, we have to gather the definitions,
- // and treat them as an argument to this block.
- //
- // 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 {
- 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.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(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.
- for i := range blk.preds {
- pred := &blk.preds[i]
- value := b.findValue(typ, variable, pred.blk)
- pred.branch.addArgumentBranchInst(b, value)
- }
- return tmpValue
- }
-}
-
-// Seal implements Builder.Seal.
-func (b *builder) Seal(raw BasicBlock) {
- blk := raw.(*basicBlock)
- if len(blk.preds) == 1 {
- blk.singlePred = blk.preds[0].blk
- }
- blk.sealed = true
-
- for _, v := range blk.unknownValues {
- variable, phiValue := v.variable, v.value
- typ := variable.getType()
- blk.addParamOn(b, phiValue)
- for i := range blk.preds {
- pred := &blk.preds[i]
- predValue := b.findValue(typ, variable, pred.blk)
- if !predValue.Valid() {
- panic("BUG: value is not defined anywhere in the predecessors in the CFG")
- }
- pred.branch.addArgumentBranchInst(b, predValue)
- }
- }
-}
-
-// Format implements Builder.Format.
-func (b *builder) Format() string {
- str := strings.Builder{}
- usedSigs := b.usedSignatures()
- if len(usedSigs) > 0 {
- str.WriteByte('\n')
- str.WriteString("signatures:\n")
- for _, sig := range usedSigs {
- str.WriteByte('\t')
- str.WriteString(sig.String())
- str.WriteByte('\n')
- }
- }
-
- var iterBegin, iterNext func() *basicBlock
- if b.doneBlockLayout {
- iterBegin, iterNext = b.blockIteratorReversePostOrderBegin, b.blockIteratorReversePostOrderNext
- } else {
- iterBegin, iterNext = b.blockIteratorBegin, b.blockIteratorNext
- }
- for bb := iterBegin(); bb != nil; bb = iterNext() {
- str.WriteByte('\n')
- str.WriteString(bb.formatHeader(b))
- str.WriteByte('\n')
-
- for cur := bb.Root(); cur != nil; cur = cur.Next() {
- str.WriteByte('\t')
- str.WriteString(cur.Format(b))
- str.WriteByte('\n')
- }
- }
- return str.String()
-}
-
-// BlockIteratorNext implements Builder.BlockIteratorNext.
-func (b *builder) BlockIteratorNext() BasicBlock {
- if blk := b.blockIteratorNext(); blk == nil {
- return nil // BasicBlock((*basicBlock)(nil)) != BasicBlock(nil)
- } else {
- return blk
- }
-}
-
-// BlockIteratorNext implements Builder.BlockIteratorNext.
-func (b *builder) blockIteratorNext() *basicBlock {
- index := b.blockIterCur
- for {
- if index == b.basicBlocksPool.Allocated() {
- return nil
- }
- ret := b.basicBlocksPool.View(index)
- index++
- if !ret.invalid {
- b.blockIterCur = index
- return ret
- }
- }
-}
-
-// BlockIteratorBegin implements Builder.BlockIteratorBegin.
-func (b *builder) BlockIteratorBegin() BasicBlock {
- return b.blockIteratorBegin()
-}
-
-// BlockIteratorBegin implements Builder.BlockIteratorBegin.
-func (b *builder) blockIteratorBegin() *basicBlock {
- b.blockIterCur = 0
- return b.blockIteratorNext()
-}
-
-// BlockIteratorReversePostOrderBegin implements Builder.BlockIteratorReversePostOrderBegin.
-func (b *builder) BlockIteratorReversePostOrderBegin() BasicBlock {
- return b.blockIteratorReversePostOrderBegin()
-}
-
-// BlockIteratorBegin implements Builder.BlockIteratorBegin.
-func (b *builder) blockIteratorReversePostOrderBegin() *basicBlock {
- b.blockIterCur = 0
- return b.blockIteratorReversePostOrderNext()
-}
-
-// BlockIteratorReversePostOrderNext implements Builder.BlockIteratorReversePostOrderNext.
-func (b *builder) BlockIteratorReversePostOrderNext() BasicBlock {
- if blk := b.blockIteratorReversePostOrderNext(); blk == nil {
- return nil // BasicBlock((*basicBlock)(nil)) != BasicBlock(nil)
- } else {
- return blk
- }
-}
-
-// BlockIteratorNext implements Builder.BlockIteratorNext.
-func (b *builder) blockIteratorReversePostOrderNext() *basicBlock {
- if b.blockIterCur >= len(b.reversePostOrderedBasicBlocks) {
- return nil
- } else {
- ret := b.reversePostOrderedBasicBlocks[b.blockIterCur]
- b.blockIterCur++
- return ret
- }
-}
-
-// 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) {
- 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.
-func (b *builder) resolveArgumentAlias(instr *Instruction) {
- if instr.v.Valid() {
- instr.v = b.resolveAlias(instr.v)
- }
-
- if instr.v2.Valid() {
- instr.v2 = b.resolveAlias(instr.v2)
- }
-
- if instr.v3.Valid() {
- instr.v3 = b.resolveAlias(instr.v3)
- }
-
- view := instr.vs.View()
- for i, v := range view {
- view[i] = b.resolveAlias(v)
- }
-}
-
-// 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 {
- vid := v.ID()
- if vid < l && info[vid].alias.Valid() {
- v = info[vid].alias
- } else {
- break
- }
- }
- return v
-}
-
-// entryBlk returns the entry block of the function.
-func (b *builder) entryBlk() *basicBlock {
- return b.basicBlocksPool.View(0)
-}
-
-// isDominatedBy returns true if the given block `n` is dominated by the given block `d`.
-// Before calling this, the builder must pass by passCalculateImmediateDominators.
-func (b *builder) isDominatedBy(n *basicBlock, d *basicBlock) bool {
- if len(b.dominators) == 0 {
- panic("BUG: passCalculateImmediateDominators must be called before calling isDominatedBy")
- }
- ent := b.entryBlk()
- doms := b.dominators
- for n != d && n != ent {
- n = doms[n.id]
- }
- return n == d
-}
-
-// BlockIDMax implements Builder.BlockIDMax.
-func (b *builder) BlockIDMax() BasicBlockID {
- return BasicBlockID(b.basicBlocksPool.Allocated())
-}
-
-// InsertUndefined implements Builder.InsertUndefined.
-func (b *builder) InsertUndefined() {
- instr := b.AllocateInstruction()
- instr.opcode = OpcodeUndefined
- b.InsertInstruction(instr)
-}
-
-// LoopNestingForestRoots implements Builder.LoopNestingForestRoots.
-func (b *builder) LoopNestingForestRoots() []BasicBlock {
- return b.loopNestingForestRoots
-}
-
-// LowestCommonAncestor implements Builder.LowestCommonAncestor.
-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/cmp.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/cmp.go
deleted file mode 100644
index 15b62ca8e..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/cmp.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package ssa
-
-// IntegerCmpCond represents a condition for integer comparison.
-type IntegerCmpCond byte
-
-const (
- // IntegerCmpCondInvalid represents an invalid condition.
- IntegerCmpCondInvalid IntegerCmpCond = iota
- // IntegerCmpCondEqual represents "==".
- IntegerCmpCondEqual
- // IntegerCmpCondNotEqual represents "!=".
- IntegerCmpCondNotEqual
- // IntegerCmpCondSignedLessThan represents Signed "<".
- IntegerCmpCondSignedLessThan
- // IntegerCmpCondSignedGreaterThanOrEqual represents Signed ">=".
- IntegerCmpCondSignedGreaterThanOrEqual
- // IntegerCmpCondSignedGreaterThan represents Signed ">".
- IntegerCmpCondSignedGreaterThan
- // IntegerCmpCondSignedLessThanOrEqual represents Signed "<=".
- IntegerCmpCondSignedLessThanOrEqual
- // IntegerCmpCondUnsignedLessThan represents Unsigned "<".
- IntegerCmpCondUnsignedLessThan
- // IntegerCmpCondUnsignedGreaterThanOrEqual represents Unsigned ">=".
- IntegerCmpCondUnsignedGreaterThanOrEqual
- // IntegerCmpCondUnsignedGreaterThan represents Unsigned ">".
- IntegerCmpCondUnsignedGreaterThan
- // IntegerCmpCondUnsignedLessThanOrEqual represents Unsigned "<=".
- IntegerCmpCondUnsignedLessThanOrEqual
-)
-
-// String implements fmt.Stringer.
-func (i IntegerCmpCond) String() string {
- switch i {
- case IntegerCmpCondEqual:
- return "eq"
- case IntegerCmpCondNotEqual:
- return "neq"
- case IntegerCmpCondSignedLessThan:
- return "lt_s"
- case IntegerCmpCondSignedGreaterThanOrEqual:
- return "ge_s"
- case IntegerCmpCondSignedGreaterThan:
- return "gt_s"
- case IntegerCmpCondSignedLessThanOrEqual:
- return "le_s"
- case IntegerCmpCondUnsignedLessThan:
- return "lt_u"
- case IntegerCmpCondUnsignedGreaterThanOrEqual:
- return "ge_u"
- case IntegerCmpCondUnsignedGreaterThan:
- return "gt_u"
- case IntegerCmpCondUnsignedLessThanOrEqual:
- return "le_u"
- default:
- panic("invalid integer comparison condition")
- }
-}
-
-// Signed returns true if the condition is signed integer comparison.
-func (i IntegerCmpCond) Signed() bool {
- switch i {
- case IntegerCmpCondSignedLessThan, IntegerCmpCondSignedGreaterThanOrEqual,
- IntegerCmpCondSignedGreaterThan, IntegerCmpCondSignedLessThanOrEqual:
- return true
- default:
- return false
- }
-}
-
-type FloatCmpCond byte
-
-const (
- // FloatCmpCondInvalid represents an invalid condition.
- FloatCmpCondInvalid FloatCmpCond = iota
- // FloatCmpCondEqual represents "==".
- FloatCmpCondEqual
- // FloatCmpCondNotEqual represents "!=".
- FloatCmpCondNotEqual
- // FloatCmpCondLessThan represents "<".
- FloatCmpCondLessThan
- // FloatCmpCondLessThanOrEqual represents "<=".
- FloatCmpCondLessThanOrEqual
- // FloatCmpCondGreaterThan represents ">".
- FloatCmpCondGreaterThan
- // FloatCmpCondGreaterThanOrEqual represents ">=".
- FloatCmpCondGreaterThanOrEqual
-)
-
-// String implements fmt.Stringer.
-func (f FloatCmpCond) String() string {
- switch f {
- case FloatCmpCondEqual:
- return "eq"
- case FloatCmpCondNotEqual:
- return "neq"
- case FloatCmpCondLessThan:
- return "lt"
- case FloatCmpCondLessThanOrEqual:
- return "le"
- case FloatCmpCondGreaterThan:
- return "gt"
- case FloatCmpCondGreaterThanOrEqual:
- return "ge"
- default:
- panic("invalid float comparison condition")
- }
-}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/funcref.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/funcref.go
deleted file mode 100644
index d9620762a..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/funcref.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package ssa
-
-import "fmt"
-
-// FuncRef is a unique identifier for a function of the frontend,
-// and is used to reference the function in function call.
-type FuncRef uint32
-
-// String implements fmt.Stringer.
-func (r FuncRef) String() string {
- return fmt.Sprintf("f%d", r)
-}
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
deleted file mode 100644
index 9a3d1da6e..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/instructions.go
+++ /dev/null
@@ -1,2976 +0,0 @@
-package ssa
-
-import (
- "fmt"
- "math"
- "strings"
-
- "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
-)
-
-// Opcode represents a SSA instruction.
-type Opcode uint32
-
-// Instruction represents an instruction whose opcode is specified by
-// Opcode. Since Go doesn't have union type, we use this flattened type
-// for all instructions, and therefore each field has different meaning
-// depending on Opcode.
-type Instruction struct {
- // id is the unique ID of this instruction which ascends from 0 following the order of program.
- id int
- opcode Opcode
- u1, u2 uint64
- v Value
- v2 Value
- v3 Value
- vs Values
- typ Type
- prev, next *Instruction
-
- // 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
- live bool
- alreadyLowered bool
-}
-
-// SourceOffset represents the offset of the source of an instruction.
-type SourceOffset int64
-
-const sourceOffsetUnknown = -1
-
-// Valid returns true if this source offset is valid.
-func (l SourceOffset) Valid() bool {
- return l != sourceOffsetUnknown
-}
-
-func (i *Instruction) annotateSourceOffset(line SourceOffset) {
- i.sourceOffset = line
-}
-
-// SourceOffset returns the source offset of this instruction.
-func (i *Instruction) SourceOffset() SourceOffset {
- return i.sourceOffset
-}
-
-// Opcode returns the opcode of this instruction.
-func (i *Instruction) Opcode() Opcode {
- return i.opcode
-}
-
-// GroupID returns the InstructionGroupID of this instruction.
-func (i *Instruction) GroupID() InstructionGroupID {
- return i.gid
-}
-
-// MarkLowered marks this instruction as already lowered.
-func (i *Instruction) MarkLowered() {
- i.alreadyLowered = true
-}
-
-// Lowered returns true if this instruction is already lowered.
-func (i *Instruction) Lowered() bool {
- return i.alreadyLowered
-}
-
-// resetInstruction resets this instruction to the initial state.
-func resetInstruction(i *Instruction) {
- *i = Instruction{}
- i.v = ValueInvalid
- i.v2 = ValueInvalid
- i.v3 = ValueInvalid
- i.rValue = ValueInvalid
- i.typ = typeInvalid
- i.vs = ValuesNil
- i.sourceOffset = sourceOffsetUnknown
-}
-
-// InstructionGroupID is assigned to each instruction and represents a group of instructions
-// where each instruction is interchangeable with others except for the last instruction
-// in the group which has side effects. In short, InstructionGroupID is determined by the side effects of instructions.
-// That means, if there's an instruction with side effect between two instructions, then these two instructions
-// will have different instructionGroupID. Note that each block always ends with branching, which is with side effects,
-// therefore, instructions in different blocks always have different InstructionGroupID(s).
-//
-// The notable application of this is used in lowering SSA-level instruction to a ISA specific instruction,
-// where we eagerly try to merge multiple instructions into single operation etc. Such merging cannot be done
-// if these instruction have different InstructionGroupID since it will change the semantics of a program.
-//
-// See passDeadCodeElimination.
-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()
-}
-
-// Return returns a Value(s) produced by this instruction if any.
-// If there's multiple return values, only the first one is returned.
-func (i *Instruction) Return() (first Value) {
- return i.rValue
-}
-
-// Args returns the arguments to this instruction.
-func (i *Instruction) Args() (v1, v2, v3 Value, vs []Value) {
- return i.v, i.v2, i.v3, i.vs.View()
-}
-
-// Arg returns the first argument to this instruction.
-func (i *Instruction) Arg() Value {
- return i.v
-}
-
-// Arg2 returns the first two arguments to this instruction.
-func (i *Instruction) Arg2() (Value, Value) {
- return i.v, i.v2
-}
-
-// ArgWithLane returns the first argument to this instruction, and the lane type.
-func (i *Instruction) ArgWithLane() (Value, VecLane) {
- return i.v, VecLane(i.u1)
-}
-
-// Arg2WithLane returns the first two arguments to this instruction, and the lane type.
-func (i *Instruction) Arg2WithLane() (Value, Value, VecLane) {
- return i.v, i.v2, VecLane(i.u1)
-}
-
-// ShuffleData returns the first two arguments to this instruction and 2 uint64s `lo`, `hi`.
-//
-// Note: Each uint64 encodes a sequence of 8 bytes where each byte encodes a VecLane,
-// so that the 128bit integer `hi<<64|lo` packs a slice `[16]VecLane`,
-// where `lane[0]` is the least significant byte, and `lane[n]` is shifted to offset `n*8`.
-func (i *Instruction) ShuffleData() (v Value, v2 Value, lo uint64, hi uint64) {
- return i.v, i.v2, i.u1, i.u2
-}
-
-// Arg3 returns the first three arguments to this instruction.
-func (i *Instruction) Arg3() (Value, Value, Value) {
- return i.v, i.v2, i.v3
-}
-
-// Next returns the next instruction laid out next to itself.
-func (i *Instruction) Next() *Instruction {
- return i.next
-}
-
-// Prev returns the previous instruction laid out prior to itself.
-func (i *Instruction) Prev() *Instruction {
- return i.prev
-}
-
-// IsBranching returns true if this instruction is a branching instruction.
-func (i *Instruction) IsBranching() bool {
- switch i.opcode {
- case OpcodeJump, OpcodeBrz, OpcodeBrnz, OpcodeBrTable:
- return true
- default:
- return false
- }
-}
-
-// TODO: complete opcode comments.
-const (
- OpcodeInvalid Opcode = iota
-
- // OpcodeUndefined is a placeholder for undefined opcode. This can be used for debugging to intentionally
- // cause a crash at certain point.
- OpcodeUndefined
-
- // OpcodeJump takes the list of args to the `block` and unconditionally jumps to it.
- OpcodeJump
-
- // OpcodeBrz branches into `blk` with `args` if the value `c` equals zero: `Brz c, blk, args`.
- OpcodeBrz
-
- // OpcodeBrnz branches into `blk` with `args` if the value `c` is not zero: `Brnz c, blk, args`.
- OpcodeBrnz
-
- // OpcodeBrTable takes the index value `index`, and branches into `labelX`. If the `index` is out of range,
- // it branches into the last labelN: `BrTable index, [label1, label2, ... labelN]`.
- OpcodeBrTable
-
- // OpcodeExitWithCode exit the execution immediately.
- OpcodeExitWithCode
-
- // OpcodeExitIfTrueWithCode exits the execution immediately if the value `c` is not zero.
- OpcodeExitIfTrueWithCode
-
- // OpcodeReturn returns from the function: `return rvalues`.
- OpcodeReturn
-
- // OpcodeCall calls a function specified by the symbol FN with arguments `args`: `returnvals = Call FN, args...`
- // This is a "near" call, which means the call target is known at compile time, and the target is relatively close
- // to this function. If the target cannot be reached by near call, the backend fails to compile.
- OpcodeCall
-
- // OpcodeCallIndirect calls a function specified by `callee` which is a function address: `returnvals = call_indirect SIG, callee, args`.
- // Note that this is different from call_indirect in Wasm, which also does type checking, etc.
- OpcodeCallIndirect
-
- // OpcodeSplat performs a vector splat operation: `v = Splat.lane x`.
- OpcodeSplat
-
- // OpcodeSwizzle performs a vector swizzle operation: `v = Swizzle.lane x, y`.
- OpcodeSwizzle
-
- // OpcodeInsertlane inserts a lane value into a vector: `v = InsertLane x, y, Idx`.
- OpcodeInsertlane
-
- // OpcodeExtractlane extracts a lane value from a vector: `v = ExtractLane x, Idx`.
- OpcodeExtractlane
-
- // OpcodeLoad loads a Type value from the [base + offset] address: `v = Load base, offset`.
- OpcodeLoad
-
- // OpcodeStore stores a Type value to the [base + offset] address: `Store v, base, offset`.
- OpcodeStore
-
- // OpcodeUload8 loads the 8-bit value from the [base + offset] address, zero-extended to 64 bits: `v = Uload8 base, offset`.
- OpcodeUload8
-
- // OpcodeSload8 loads the 8-bit value from the [base + offset] address, sign-extended to 64 bits: `v = Sload8 base, offset`.
- OpcodeSload8
-
- // OpcodeIstore8 stores the 8-bit value to the [base + offset] address, sign-extended to 64 bits: `Istore8 v, base, offset`.
- OpcodeIstore8
-
- // OpcodeUload16 loads the 16-bit value from the [base + offset] address, zero-extended to 64 bits: `v = Uload16 base, offset`.
- OpcodeUload16
-
- // OpcodeSload16 loads the 16-bit value from the [base + offset] address, sign-extended to 64 bits: `v = Sload16 base, offset`.
- OpcodeSload16
-
- // OpcodeIstore16 stores the 16-bit value to the [base + offset] address, zero-extended to 64 bits: `Istore16 v, base, offset`.
- OpcodeIstore16
-
- // OpcodeUload32 loads the 32-bit value from the [base + offset] address, zero-extended to 64 bits: `v = Uload32 base, offset`.
- OpcodeUload32
-
- // OpcodeSload32 loads the 32-bit value from the [base + offset] address, sign-extended to 64 bits: `v = Sload32 base, offset`.
- OpcodeSload32
-
- // OpcodeIstore32 stores the 32-bit value to the [base + offset] address, zero-extended to 64 bits: `Istore16 v, base, offset`.
- OpcodeIstore32
-
- // OpcodeLoadSplat represents a load that replicates the loaded value to all lanes `v = LoadSplat.lane p, Offset`.
- OpcodeLoadSplat
-
- // OpcodeVZeroExtLoad loads a scalar single/double precision floating point value from the [p + Offset] address,
- // and zero-extend it to the V128 value: `v = VExtLoad p, Offset`.
- OpcodeVZeroExtLoad
-
- // OpcodeIconst represents the integer const.
- OpcodeIconst
-
- // OpcodeF32const represents the single-precision const.
- OpcodeF32const
-
- // OpcodeF64const represents the double-precision const.
- OpcodeF64const
-
- // OpcodeVconst represents the 128bit vector const.
- OpcodeVconst
-
- // OpcodeVbor computes binary or between two 128bit vectors: `v = bor x, y`.
- OpcodeVbor
-
- // OpcodeVbxor computes binary xor between two 128bit vectors: `v = bxor x, y`.
- OpcodeVbxor
-
- // OpcodeVband computes binary and between two 128bit vectors: `v = band x, y`.
- OpcodeVband
-
- // OpcodeVbandnot computes binary and-not between two 128bit vectors: `v = bandnot x, y`.
- OpcodeVbandnot
-
- // OpcodeVbnot negates a 128bit vector: `v = bnot x`.
- OpcodeVbnot
-
- // OpcodeVbitselect uses the bits in the control mask c to select the corresponding bit from x when 1
- // and y when 0: `v = bitselect c, x, y`.
- OpcodeVbitselect
-
- // OpcodeShuffle shuffles two vectors using the given 128-bit immediate: `v = shuffle imm, x, y`.
- // For each byte in the immediate, a value i in [0, 15] selects the i-th byte in vector x;
- // i in [16, 31] selects the (i-16)-th byte in vector y.
- OpcodeShuffle
-
- // OpcodeSelect chooses between two values based on a condition `c`: `v = Select c, x, y`.
- OpcodeSelect
-
- // OpcodeVanyTrue performs a any true operation: `s = VanyTrue a`.
- OpcodeVanyTrue
-
- // OpcodeVallTrue performs a lane-wise all true operation: `s = VallTrue.lane a`.
- OpcodeVallTrue
-
- // OpcodeVhighBits performs a lane-wise extract of the high bits: `v = VhighBits.lane a`.
- OpcodeVhighBits
-
- // OpcodeIcmp compares two integer values with the given condition: `v = icmp Cond, x, y`.
- OpcodeIcmp
-
- // OpcodeVIcmp compares two integer values with the given condition: `v = vicmp Cond, x, y` on vector.
- OpcodeVIcmp
-
- // OpcodeIcmpImm compares an integer value with the immediate value on the given condition: `v = icmp_imm Cond, x, Y`.
- OpcodeIcmpImm
-
- // OpcodeIadd performs an integer addition: `v = Iadd x, y`.
- OpcodeIadd
-
- // OpcodeVIadd performs an integer addition: `v = VIadd.lane x, y` on vector.
- OpcodeVIadd
-
- // OpcodeVSaddSat performs a signed saturating vector addition: `v = VSaddSat.lane x, y` on vector.
- OpcodeVSaddSat
-
- // OpcodeVUaddSat performs an unsigned saturating vector addition: `v = VUaddSat.lane x, y` on vector.
- OpcodeVUaddSat
-
- // OpcodeIsub performs an integer subtraction: `v = Isub x, y`.
- OpcodeIsub
-
- // OpcodeVIsub performs an integer subtraction: `v = VIsub.lane x, y` on vector.
- OpcodeVIsub
-
- // OpcodeVSsubSat performs a signed saturating vector subtraction: `v = VSsubSat.lane x, y` on vector.
- OpcodeVSsubSat
-
- // OpcodeVUsubSat performs an unsigned saturating vector subtraction: `v = VUsubSat.lane x, y` on vector.
- OpcodeVUsubSat
-
- // OpcodeVImin performs a signed integer min: `v = VImin.lane x, y` on vector.
- OpcodeVImin
-
- // OpcodeVUmin performs an unsigned integer min: `v = VUmin.lane x, y` on vector.
- OpcodeVUmin
-
- // OpcodeVImax performs a signed integer max: `v = VImax.lane x, y` on vector.
- OpcodeVImax
-
- // OpcodeVUmax performs an unsigned integer max: `v = VUmax.lane x, y` on vector.
- OpcodeVUmax
-
- // OpcodeVAvgRound performs an unsigned integer avg, truncating to zero: `v = VAvgRound.lane x, y` on vector.
- OpcodeVAvgRound
-
- // OpcodeVImul performs an integer multiplication: `v = VImul.lane x, y` on vector.
- OpcodeVImul
-
- // OpcodeVIneg negates the given integer vector value: `v = VIneg x`.
- OpcodeVIneg
-
- // OpcodeVIpopcnt counts the number of 1-bits in the given vector: `v = VIpopcnt x`.
- OpcodeVIpopcnt
-
- // OpcodeVIabs returns the absolute value for the given vector value: `v = VIabs.lane x`.
- OpcodeVIabs
-
- // OpcodeVIshl shifts x left by (y mod lane-width): `v = VIshl.lane x, y` on vector.
- OpcodeVIshl
-
- // OpcodeVUshr shifts x right by (y mod lane-width), unsigned: `v = VUshr.lane x, y` on vector.
- OpcodeVUshr
-
- // OpcodeVSshr shifts x right by (y mod lane-width), signed: `v = VSshr.lane x, y` on vector.
- OpcodeVSshr
-
- // OpcodeVFabs takes the absolute value of a floating point value: `v = VFabs.lane x on vector.
- OpcodeVFabs
-
- // OpcodeVFmax takes the maximum of two floating point values: `v = VFmax.lane x, y on vector.
- OpcodeVFmax
-
- // OpcodeVFmin takes the minimum of two floating point values: `v = VFmin.lane x, y on vector.
- OpcodeVFmin
-
- // OpcodeVFneg negates the given floating point vector value: `v = VFneg x`.
- OpcodeVFneg
-
- // OpcodeVFadd performs a floating point addition: `v = VFadd.lane x, y` on vector.
- OpcodeVFadd
-
- // OpcodeVFsub performs a floating point subtraction: `v = VFsub.lane x, y` on vector.
- OpcodeVFsub
-
- // OpcodeVFmul performs a floating point multiplication: `v = VFmul.lane x, y` on vector.
- OpcodeVFmul
-
- // OpcodeVFdiv performs a floating point division: `v = VFdiv.lane x, y` on vector.
- OpcodeVFdiv
-
- // OpcodeVFcmp compares two float values with the given condition: `v = VFcmp.lane Cond, x, y` on float.
- OpcodeVFcmp
-
- // OpcodeVCeil takes the ceiling of the given floating point value: `v = ceil.lane x` on vector.
- OpcodeVCeil
-
- // OpcodeVFloor takes the floor of the given floating point value: `v = floor.lane x` on vector.
- OpcodeVFloor
-
- // OpcodeVTrunc takes the truncation of the given floating point value: `v = trunc.lane x` on vector.
- OpcodeVTrunc
-
- // OpcodeVNearest takes the nearest integer of the given floating point value: `v = nearest.lane x` on vector.
- OpcodeVNearest
-
- // OpcodeVMaxPseudo computes the lane-wise maximum value `v = VMaxPseudo.lane x, y` on vector defined as `x < y ? x : y`.
- OpcodeVMaxPseudo
-
- // OpcodeVMinPseudo computes the lane-wise minimum value `v = VMinPseudo.lane x, y` on vector defined as `y < x ? x : y`.
- OpcodeVMinPseudo
-
- // OpcodeVSqrt takes the minimum of two floating point values: `v = VFmin.lane x, y` on vector.
- OpcodeVSqrt
-
- // OpcodeVFcvtToUintSat converts a floating point value to an unsigned integer: `v = FcvtToUintSat.lane x` on vector.
- OpcodeVFcvtToUintSat
-
- // OpcodeVFcvtToSintSat converts a floating point value to a signed integer: `v = VFcvtToSintSat.lane x` on vector.
- OpcodeVFcvtToSintSat
-
- // OpcodeVFcvtFromUint converts a floating point value from an unsigned integer: `v = FcvtFromUint.lane x` on vector.
- // x is always a 32-bit integer lane, and the result is either a 32-bit or 64-bit floating point-sized vector.
- OpcodeVFcvtFromUint
-
- // OpcodeVFcvtFromSint converts a floating point value from a signed integer: `v = VFcvtFromSint.lane x` on vector.
- // x is always a 32-bit integer lane, and the result is either a 32-bit or 64-bit floating point-sized vector.
- OpcodeVFcvtFromSint
-
- // OpcodeImul performs an integer multiplication: `v = Imul x, y`.
- OpcodeImul
-
- // OpcodeUdiv performs the unsigned integer division `v = Udiv x, y`.
- OpcodeUdiv
-
- // OpcodeSdiv performs the signed integer division `v = Sdiv x, y`.
- OpcodeSdiv
-
- // OpcodeUrem computes the remainder of the unsigned integer division `v = Urem x, y`.
- OpcodeUrem
-
- // OpcodeSrem computes the remainder of the signed integer division `v = Srem x, y`.
- OpcodeSrem
-
- // OpcodeBand performs a binary and: `v = Band x, y`.
- OpcodeBand
-
- // OpcodeBor performs a binary or: `v = Bor x, y`.
- OpcodeBor
-
- // OpcodeBxor performs a binary xor: `v = Bxor x, y`.
- OpcodeBxor
-
- // OpcodeBnot performs a binary not: `v = Bnot x`.
- OpcodeBnot
-
- // OpcodeRotl rotates the given integer value to the left: `v = Rotl x, y`.
- OpcodeRotl
-
- // OpcodeRotr rotates the given integer value to the right: `v = Rotr x, y`.
- OpcodeRotr
-
- // OpcodeIshl does logical shift left: `v = Ishl x, y`.
- OpcodeIshl
-
- // OpcodeUshr does logical shift right: `v = Ushr x, y`.
- OpcodeUshr
-
- // OpcodeSshr does arithmetic shift right: `v = Sshr x, y`.
- OpcodeSshr
-
- // OpcodeClz counts the number of leading zeros: `v = clz x`.
- OpcodeClz
-
- // OpcodeCtz counts the number of trailing zeros: `v = ctz x`.
- OpcodeCtz
-
- // OpcodePopcnt counts the number of 1-bits: `v = popcnt x`.
- OpcodePopcnt
-
- // OpcodeFcmp compares two floating point values: `v = fcmp Cond, x, y`.
- OpcodeFcmp
-
- // OpcodeFadd performs a floating point addition: / `v = Fadd x, y`.
- OpcodeFadd
-
- // OpcodeFsub performs a floating point subtraction: `v = Fsub x, y`.
- OpcodeFsub
-
- // OpcodeFmul performs a floating point multiplication: `v = Fmul x, y`.
- OpcodeFmul
-
- // OpcodeSqmulRoundSat performs a lane-wise saturating rounding multiplication
- // in Q15 format: `v = SqmulRoundSat.lane x,y` on vector.
- OpcodeSqmulRoundSat
-
- // OpcodeFdiv performs a floating point division: `v = Fdiv x, y`.
- OpcodeFdiv
-
- // OpcodeSqrt takes the square root of the given floating point value: `v = sqrt x`.
- OpcodeSqrt
-
- // OpcodeFneg negates the given floating point value: `v = Fneg x`.
- OpcodeFneg
-
- // OpcodeFabs takes the absolute value of the given floating point value: `v = fabs x`.
- OpcodeFabs
-
- // OpcodeFcopysign copies the sign of the second floating point value to the first floating point value:
- // `v = Fcopysign x, y`.
- OpcodeFcopysign
-
- // OpcodeFmin takes the minimum of two floating point values: `v = fmin x, y`.
- OpcodeFmin
-
- // OpcodeFmax takes the maximum of two floating point values: `v = fmax x, y`.
- OpcodeFmax
-
- // OpcodeCeil takes the ceiling of the given floating point value: `v = ceil x`.
- OpcodeCeil
-
- // OpcodeFloor takes the floor of the given floating point value: `v = floor x`.
- OpcodeFloor
-
- // OpcodeTrunc takes the truncation of the given floating point value: `v = trunc x`.
- OpcodeTrunc
-
- // OpcodeNearest takes the nearest integer of the given floating point value: `v = nearest x`.
- OpcodeNearest
-
- // OpcodeBitcast is a bitcast operation: `v = bitcast x`.
- OpcodeBitcast
-
- // OpcodeIreduce narrow the given integer: `v = Ireduce x`.
- OpcodeIreduce
-
- // OpcodeSnarrow converts two input vectors x, y into a smaller lane vector by narrowing each lane, signed `v = Snarrow.lane x, y`.
- OpcodeSnarrow
-
- // OpcodeUnarrow converts two input vectors x, y into a smaller lane vector by narrowing each lane, unsigned `v = Unarrow.lane x, y`.
- OpcodeUnarrow
-
- // OpcodeSwidenLow converts low half of the smaller lane vector to a larger lane vector, sign extended: `v = SwidenLow.lane x`.
- OpcodeSwidenLow
-
- // OpcodeSwidenHigh converts high half of the smaller lane vector to a larger lane vector, sign extended: `v = SwidenHigh.lane x`.
- OpcodeSwidenHigh
-
- // OpcodeUwidenLow converts low half of the smaller lane vector to a larger lane vector, zero (unsigned) extended: `v = UwidenLow.lane x`.
- OpcodeUwidenLow
-
- // OpcodeUwidenHigh converts high half of the smaller lane vector to a larger lane vector, zero (unsigned) extended: `v = UwidenHigh.lane x`.
- OpcodeUwidenHigh
-
- // OpcodeExtIaddPairwise is a lane-wise integer extended pairwise addition producing extended results (twice wider results than the inputs): `v = extiadd_pairwise x, y` on vector.
- OpcodeExtIaddPairwise
-
- // OpcodeWideningPairwiseDotProductS is a lane-wise widening pairwise dot product with signed saturation: `v = WideningPairwiseDotProductS x, y` on vector.
- // Currently, the only lane is i16, and the result is i32.
- OpcodeWideningPairwiseDotProductS
-
- // OpcodeUExtend zero-extends the given integer: `v = UExtend x, from->to`.
- OpcodeUExtend
-
- // OpcodeSExtend sign-extends the given integer: `v = SExtend x, from->to`.
- OpcodeSExtend
-
- // OpcodeFpromote promotes the given floating point value: `v = Fpromote x`.
- OpcodeFpromote
-
- // OpcodeFvpromoteLow converts the two lower single-precision floating point lanes
- // to the two double-precision lanes of the result: `v = FvpromoteLow.lane x` on vector.
- OpcodeFvpromoteLow
-
- // OpcodeFdemote demotes the given float point value: `v = Fdemote x`.
- OpcodeFdemote
-
- // OpcodeFvdemote converts the two double-precision floating point lanes
- // to two lower single-precision lanes of the result `v = Fvdemote.lane x`.
- OpcodeFvdemote
-
- // OpcodeFcvtToUint converts a floating point value to an unsigned integer: `v = FcvtToUint x`.
- OpcodeFcvtToUint
-
- // OpcodeFcvtToSint converts a floating point value to a signed integer: `v = FcvtToSint x`.
- OpcodeFcvtToSint
-
- // OpcodeFcvtToUintSat converts a floating point value to an unsigned integer: `v = FcvtToUintSat x` which saturates on overflow.
- OpcodeFcvtToUintSat
-
- // OpcodeFcvtToSintSat converts a floating point value to a signed integer: `v = FcvtToSintSat x` which saturates on overflow.
- OpcodeFcvtToSintSat
-
- // OpcodeFcvtFromUint converts an unsigned integer to a floating point value: `v = FcvtFromUint x`.
- OpcodeFcvtFromUint
-
- // OpcodeFcvtFromSint converts a signed integer to a floating point value: `v = FcvtFromSint x`.
- OpcodeFcvtFromSint
-
- // OpcodeAtomicRmw is atomic read-modify-write operation: `v = atomic_rmw op, p, offset, value`.
- OpcodeAtomicRmw
-
- // OpcodeAtomicCas is atomic compare-and-swap operation.
- OpcodeAtomicCas
-
- // OpcodeAtomicLoad is atomic load operation.
- OpcodeAtomicLoad
-
- // OpcodeAtomicStore is atomic store operation.
- OpcodeAtomicStore
-
- // OpcodeFence is a memory fence operation.
- OpcodeFence
-
- // opcodeEnd marks the end of the opcode list.
- opcodeEnd
-)
-
-// AtomicRmwOp represents the atomic read-modify-write operation.
-type AtomicRmwOp byte
-
-const (
- // AtomicRmwOpAdd is an atomic add operation.
- AtomicRmwOpAdd AtomicRmwOp = iota
- // AtomicRmwOpSub is an atomic sub operation.
- AtomicRmwOpSub
- // AtomicRmwOpAnd is an atomic and operation.
- AtomicRmwOpAnd
- // AtomicRmwOpOr is an atomic or operation.
- AtomicRmwOpOr
- // AtomicRmwOpXor is an atomic xor operation.
- AtomicRmwOpXor
- // AtomicRmwOpXchg is an atomic swap operation.
- AtomicRmwOpXchg
-)
-
-// String implements the fmt.Stringer.
-func (op AtomicRmwOp) String() string {
- switch op {
- case AtomicRmwOpAdd:
- return "add"
- case AtomicRmwOpSub:
- return "sub"
- case AtomicRmwOpAnd:
- return "and"
- case AtomicRmwOpOr:
- return "or"
- case AtomicRmwOpXor:
- return "xor"
- case AtomicRmwOpXchg:
- return "xchg"
- }
- panic(fmt.Sprintf("unknown AtomicRmwOp: %d", op))
-}
-
-// returnTypesFn provides the info to determine the type of instruction.
-// t1 is the type of the first result, ts are the types of the remaining results.
-type returnTypesFn func(b *builder, instr *Instruction) (t1 Type, ts []Type)
-
-var (
- returnTypesFnNoReturns returnTypesFn = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return typeInvalid, nil }
- returnTypesFnSingle = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return instr.typ, nil }
- returnTypesFnI32 = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeI32, nil }
- returnTypesFnF32 = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeF32, nil }
- returnTypesFnF64 = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeF64, nil }
- returnTypesFnV128 = func(b *builder, instr *Instruction) (t1 Type, ts []Type) { return TypeV128, nil }
-)
-
-// sideEffect provides the info to determine if an instruction has side effects which
-// is used to determine if it can be optimized out, interchanged with others, etc.
-type sideEffect byte
-
-const (
- sideEffectUnknown sideEffect = iota
- // sideEffectStrict represents an instruction with side effects, and should be always alive plus cannot be reordered.
- sideEffectStrict
- // sideEffectTraps represents an instruction that can trap, and should be always alive but can be reordered within the group.
- sideEffectTraps
- // sideEffectNone represents an instruction without side effects, and can be eliminated if the result is not used, plus can be reordered within the group.
- sideEffectNone
-)
-
-// instructionSideEffects provides the info to determine if an instruction has side effects.
-// Instructions with side effects must not be eliminated regardless whether the result is used or not.
-var instructionSideEffects = [opcodeEnd]sideEffect{
- OpcodeUndefined: sideEffectStrict,
- OpcodeJump: sideEffectStrict,
- OpcodeIconst: sideEffectNone,
- OpcodeCall: sideEffectStrict,
- OpcodeCallIndirect: sideEffectStrict,
- OpcodeIadd: sideEffectNone,
- OpcodeImul: sideEffectNone,
- OpcodeIsub: sideEffectNone,
- OpcodeIcmp: sideEffectNone,
- OpcodeExtractlane: sideEffectNone,
- OpcodeInsertlane: sideEffectNone,
- OpcodeBand: sideEffectNone,
- OpcodeBor: sideEffectNone,
- OpcodeBxor: sideEffectNone,
- OpcodeRotl: sideEffectNone,
- OpcodeRotr: sideEffectNone,
- OpcodeFcmp: sideEffectNone,
- OpcodeFadd: sideEffectNone,
- OpcodeClz: sideEffectNone,
- OpcodeCtz: sideEffectNone,
- OpcodePopcnt: sideEffectNone,
- OpcodeLoad: sideEffectNone,
- OpcodeLoadSplat: sideEffectNone,
- OpcodeUload8: sideEffectNone,
- OpcodeUload16: sideEffectNone,
- OpcodeUload32: sideEffectNone,
- OpcodeSload8: sideEffectNone,
- OpcodeSload16: sideEffectNone,
- OpcodeSload32: sideEffectNone,
- OpcodeSExtend: sideEffectNone,
- OpcodeUExtend: sideEffectNone,
- OpcodeSwidenLow: sideEffectNone,
- OpcodeUwidenLow: sideEffectNone,
- OpcodeSwidenHigh: sideEffectNone,
- OpcodeUwidenHigh: sideEffectNone,
- OpcodeSnarrow: sideEffectNone,
- OpcodeUnarrow: sideEffectNone,
- OpcodeSwizzle: sideEffectNone,
- OpcodeShuffle: sideEffectNone,
- OpcodeSplat: sideEffectNone,
- OpcodeFsub: sideEffectNone,
- OpcodeF32const: sideEffectNone,
- OpcodeF64const: sideEffectNone,
- OpcodeIshl: sideEffectNone,
- OpcodeSshr: sideEffectNone,
- OpcodeUshr: sideEffectNone,
- OpcodeStore: sideEffectStrict,
- OpcodeIstore8: sideEffectStrict,
- OpcodeIstore16: sideEffectStrict,
- OpcodeIstore32: sideEffectStrict,
- OpcodeExitWithCode: sideEffectStrict,
- OpcodeExitIfTrueWithCode: sideEffectStrict,
- OpcodeReturn: sideEffectStrict,
- OpcodeBrz: sideEffectStrict,
- OpcodeBrnz: sideEffectStrict,
- OpcodeBrTable: sideEffectStrict,
- OpcodeFdiv: sideEffectNone,
- OpcodeFmul: sideEffectNone,
- OpcodeFmax: sideEffectNone,
- OpcodeSqmulRoundSat: sideEffectNone,
- OpcodeSelect: sideEffectNone,
- OpcodeFmin: sideEffectNone,
- OpcodeFneg: sideEffectNone,
- OpcodeFcvtToSint: sideEffectTraps,
- OpcodeFcvtToUint: sideEffectTraps,
- OpcodeFcvtFromSint: sideEffectNone,
- OpcodeFcvtFromUint: sideEffectNone,
- OpcodeFcvtToSintSat: sideEffectNone,
- OpcodeFcvtToUintSat: sideEffectNone,
- OpcodeVFcvtFromUint: sideEffectNone,
- OpcodeVFcvtFromSint: sideEffectNone,
- OpcodeFdemote: sideEffectNone,
- OpcodeFvpromoteLow: sideEffectNone,
- OpcodeFvdemote: sideEffectNone,
- OpcodeFpromote: sideEffectNone,
- OpcodeBitcast: sideEffectNone,
- OpcodeIreduce: sideEffectNone,
- OpcodeSqrt: sideEffectNone,
- OpcodeCeil: sideEffectNone,
- OpcodeFloor: sideEffectNone,
- OpcodeTrunc: sideEffectNone,
- OpcodeNearest: sideEffectNone,
- OpcodeSdiv: sideEffectTraps,
- OpcodeSrem: sideEffectTraps,
- OpcodeUdiv: sideEffectTraps,
- OpcodeUrem: sideEffectTraps,
- OpcodeFabs: sideEffectNone,
- OpcodeFcopysign: sideEffectNone,
- OpcodeExtIaddPairwise: sideEffectNone,
- OpcodeVconst: sideEffectNone,
- OpcodeVbor: sideEffectNone,
- OpcodeVbxor: sideEffectNone,
- OpcodeVband: sideEffectNone,
- OpcodeVbandnot: sideEffectNone,
- OpcodeVbnot: sideEffectNone,
- OpcodeVbitselect: sideEffectNone,
- OpcodeVanyTrue: sideEffectNone,
- OpcodeVallTrue: sideEffectNone,
- OpcodeVhighBits: sideEffectNone,
- OpcodeVIadd: sideEffectNone,
- OpcodeVSaddSat: sideEffectNone,
- OpcodeVUaddSat: sideEffectNone,
- OpcodeVIsub: sideEffectNone,
- OpcodeVSsubSat: sideEffectNone,
- OpcodeVUsubSat: sideEffectNone,
- OpcodeVIcmp: sideEffectNone,
- OpcodeVImin: sideEffectNone,
- OpcodeVUmin: sideEffectNone,
- OpcodeVImax: sideEffectNone,
- OpcodeVUmax: sideEffectNone,
- OpcodeVAvgRound: sideEffectNone,
- OpcodeVImul: sideEffectNone,
- OpcodeVIabs: sideEffectNone,
- OpcodeVIneg: sideEffectNone,
- OpcodeVIpopcnt: sideEffectNone,
- OpcodeVIshl: sideEffectNone,
- OpcodeVSshr: sideEffectNone,
- OpcodeVUshr: sideEffectNone,
- OpcodeVSqrt: sideEffectNone,
- OpcodeVFabs: sideEffectNone,
- OpcodeVFmin: sideEffectNone,
- OpcodeVFmax: sideEffectNone,
- OpcodeVFneg: sideEffectNone,
- OpcodeVFadd: sideEffectNone,
- OpcodeVFsub: sideEffectNone,
- OpcodeVFmul: sideEffectNone,
- OpcodeVFdiv: sideEffectNone,
- OpcodeVFcmp: sideEffectNone,
- OpcodeVCeil: sideEffectNone,
- OpcodeVFloor: sideEffectNone,
- OpcodeVTrunc: sideEffectNone,
- OpcodeVNearest: sideEffectNone,
- OpcodeVMaxPseudo: sideEffectNone,
- OpcodeVMinPseudo: sideEffectNone,
- OpcodeVFcvtToUintSat: sideEffectNone,
- OpcodeVFcvtToSintSat: sideEffectNone,
- OpcodeVZeroExtLoad: sideEffectNone,
- OpcodeAtomicRmw: sideEffectStrict,
- OpcodeAtomicLoad: sideEffectStrict,
- OpcodeAtomicStore: sideEffectStrict,
- OpcodeAtomicCas: sideEffectStrict,
- OpcodeFence: sideEffectStrict,
- OpcodeWideningPairwiseDotProductS: sideEffectNone,
-}
-
-// sideEffect returns true if this instruction has side effects.
-func (i *Instruction) sideEffect() sideEffect {
- if e := instructionSideEffects[i.opcode]; e == sideEffectUnknown {
- panic("BUG: side effect info not registered for " + i.opcode.String())
- } else {
- return e
- }
-}
-
-// instructionReturnTypes provides the function to determine the return types of an instruction.
-var instructionReturnTypes = [opcodeEnd]returnTypesFn{
- OpcodeExtIaddPairwise: returnTypesFnV128,
- OpcodeVbor: returnTypesFnV128,
- OpcodeVbxor: returnTypesFnV128,
- OpcodeVband: returnTypesFnV128,
- OpcodeVbnot: returnTypesFnV128,
- OpcodeVbandnot: returnTypesFnV128,
- OpcodeVbitselect: returnTypesFnV128,
- OpcodeVanyTrue: returnTypesFnI32,
- OpcodeVallTrue: returnTypesFnI32,
- OpcodeVhighBits: returnTypesFnI32,
- OpcodeVIadd: returnTypesFnV128,
- OpcodeVSaddSat: returnTypesFnV128,
- OpcodeVUaddSat: returnTypesFnV128,
- OpcodeVIsub: returnTypesFnV128,
- OpcodeVSsubSat: returnTypesFnV128,
- OpcodeVUsubSat: returnTypesFnV128,
- OpcodeVIcmp: returnTypesFnV128,
- OpcodeVImin: returnTypesFnV128,
- OpcodeVUmin: returnTypesFnV128,
- OpcodeVImax: returnTypesFnV128,
- OpcodeVUmax: returnTypesFnV128,
- OpcodeVImul: returnTypesFnV128,
- OpcodeVAvgRound: returnTypesFnV128,
- OpcodeVIabs: returnTypesFnV128,
- OpcodeVIneg: returnTypesFnV128,
- OpcodeVIpopcnt: returnTypesFnV128,
- OpcodeVIshl: returnTypesFnV128,
- OpcodeVSshr: returnTypesFnV128,
- OpcodeVUshr: returnTypesFnV128,
- OpcodeExtractlane: returnTypesFnSingle,
- OpcodeInsertlane: returnTypesFnV128,
- OpcodeBand: returnTypesFnSingle,
- OpcodeFcopysign: returnTypesFnSingle,
- OpcodeBitcast: returnTypesFnSingle,
- OpcodeBor: returnTypesFnSingle,
- OpcodeBxor: returnTypesFnSingle,
- OpcodeRotl: returnTypesFnSingle,
- OpcodeRotr: returnTypesFnSingle,
- OpcodeIshl: returnTypesFnSingle,
- OpcodeSshr: returnTypesFnSingle,
- OpcodeSdiv: returnTypesFnSingle,
- OpcodeSrem: returnTypesFnSingle,
- OpcodeUdiv: returnTypesFnSingle,
- OpcodeUrem: returnTypesFnSingle,
- OpcodeUshr: returnTypesFnSingle,
- OpcodeJump: returnTypesFnNoReturns,
- OpcodeUndefined: returnTypesFnNoReturns,
- OpcodeIconst: returnTypesFnSingle,
- OpcodeSelect: returnTypesFnSingle,
- OpcodeSExtend: returnTypesFnSingle,
- OpcodeUExtend: returnTypesFnSingle,
- OpcodeSwidenLow: returnTypesFnV128,
- OpcodeUwidenLow: returnTypesFnV128,
- OpcodeSwidenHigh: returnTypesFnV128,
- OpcodeUwidenHigh: returnTypesFnV128,
- OpcodeSnarrow: returnTypesFnV128,
- OpcodeUnarrow: returnTypesFnV128,
- OpcodeSwizzle: returnTypesFnSingle,
- OpcodeShuffle: returnTypesFnV128,
- OpcodeSplat: returnTypesFnV128,
- OpcodeIreduce: returnTypesFnSingle,
- OpcodeFabs: returnTypesFnSingle,
- OpcodeSqrt: returnTypesFnSingle,
- OpcodeCeil: returnTypesFnSingle,
- OpcodeFloor: returnTypesFnSingle,
- OpcodeTrunc: returnTypesFnSingle,
- OpcodeNearest: returnTypesFnSingle,
- OpcodeCallIndirect: func(b *builder, instr *Instruction) (t1 Type, ts []Type) {
- sigID := SignatureID(instr.u1)
- sig, ok := b.signatures[sigID]
- if !ok {
- panic("BUG")
- }
- switch len(sig.Results) {
- case 0:
- t1 = typeInvalid
- case 1:
- t1 = sig.Results[0]
- default:
- t1, ts = sig.Results[0], sig.Results[1:]
- }
- return
- },
- OpcodeCall: func(b *builder, instr *Instruction) (t1 Type, ts []Type) {
- sigID := SignatureID(instr.u2)
- sig, ok := b.signatures[sigID]
- if !ok {
- panic("BUG")
- }
- switch len(sig.Results) {
- case 0:
- t1 = typeInvalid
- case 1:
- t1 = sig.Results[0]
- default:
- t1, ts = sig.Results[0], sig.Results[1:]
- }
- return
- },
- OpcodeLoad: returnTypesFnSingle,
- OpcodeVZeroExtLoad: returnTypesFnV128,
- OpcodeLoadSplat: returnTypesFnV128,
- OpcodeIadd: returnTypesFnSingle,
- OpcodeIsub: returnTypesFnSingle,
- OpcodeImul: returnTypesFnSingle,
- OpcodeIcmp: returnTypesFnI32,
- OpcodeFcmp: returnTypesFnI32,
- OpcodeFadd: returnTypesFnSingle,
- OpcodeFsub: returnTypesFnSingle,
- OpcodeFdiv: returnTypesFnSingle,
- OpcodeFmul: returnTypesFnSingle,
- OpcodeFmax: returnTypesFnSingle,
- OpcodeFmin: returnTypesFnSingle,
- OpcodeSqmulRoundSat: returnTypesFnV128,
- OpcodeF32const: returnTypesFnF32,
- OpcodeF64const: returnTypesFnF64,
- OpcodeClz: returnTypesFnSingle,
- OpcodeCtz: returnTypesFnSingle,
- OpcodePopcnt: returnTypesFnSingle,
- OpcodeStore: returnTypesFnNoReturns,
- OpcodeIstore8: returnTypesFnNoReturns,
- OpcodeIstore16: returnTypesFnNoReturns,
- OpcodeIstore32: returnTypesFnNoReturns,
- OpcodeExitWithCode: returnTypesFnNoReturns,
- OpcodeExitIfTrueWithCode: returnTypesFnNoReturns,
- OpcodeReturn: returnTypesFnNoReturns,
- OpcodeBrz: returnTypesFnNoReturns,
- OpcodeBrnz: returnTypesFnNoReturns,
- OpcodeBrTable: returnTypesFnNoReturns,
- OpcodeUload8: returnTypesFnSingle,
- OpcodeUload16: returnTypesFnSingle,
- OpcodeUload32: returnTypesFnSingle,
- OpcodeSload8: returnTypesFnSingle,
- OpcodeSload16: returnTypesFnSingle,
- OpcodeSload32: returnTypesFnSingle,
- OpcodeFcvtToSint: returnTypesFnSingle,
- OpcodeFcvtToUint: returnTypesFnSingle,
- OpcodeFcvtFromSint: returnTypesFnSingle,
- OpcodeFcvtFromUint: returnTypesFnSingle,
- OpcodeFcvtToSintSat: returnTypesFnSingle,
- OpcodeFcvtToUintSat: returnTypesFnSingle,
- OpcodeVFcvtFromUint: returnTypesFnV128,
- OpcodeVFcvtFromSint: returnTypesFnV128,
- OpcodeFneg: returnTypesFnSingle,
- OpcodeFdemote: returnTypesFnF32,
- OpcodeFvdemote: returnTypesFnV128,
- OpcodeFvpromoteLow: returnTypesFnV128,
- OpcodeFpromote: returnTypesFnF64,
- OpcodeVconst: returnTypesFnV128,
- OpcodeVFabs: returnTypesFnV128,
- OpcodeVSqrt: returnTypesFnV128,
- OpcodeVFmax: returnTypesFnV128,
- OpcodeVFmin: returnTypesFnV128,
- OpcodeVFneg: returnTypesFnV128,
- OpcodeVFadd: returnTypesFnV128,
- OpcodeVFsub: returnTypesFnV128,
- OpcodeVFmul: returnTypesFnV128,
- OpcodeVFdiv: returnTypesFnV128,
- OpcodeVFcmp: returnTypesFnV128,
- OpcodeVCeil: returnTypesFnV128,
- OpcodeVFloor: returnTypesFnV128,
- OpcodeVTrunc: returnTypesFnV128,
- OpcodeVNearest: returnTypesFnV128,
- OpcodeVMaxPseudo: returnTypesFnV128,
- OpcodeVMinPseudo: returnTypesFnV128,
- OpcodeVFcvtToUintSat: returnTypesFnV128,
- OpcodeVFcvtToSintSat: returnTypesFnV128,
- OpcodeAtomicRmw: returnTypesFnSingle,
- OpcodeAtomicLoad: returnTypesFnSingle,
- OpcodeAtomicStore: returnTypesFnNoReturns,
- OpcodeAtomicCas: returnTypesFnSingle,
- OpcodeFence: returnTypesFnNoReturns,
- OpcodeWideningPairwiseDotProductS: returnTypesFnV128,
-}
-
-// AsLoad initializes this instruction as a store instruction with OpcodeLoad.
-func (i *Instruction) AsLoad(ptr Value, offset uint32, typ Type) *Instruction {
- i.opcode = OpcodeLoad
- i.v = ptr
- i.u1 = uint64(offset)
- i.typ = typ
- return i
-}
-
-// AsExtLoad initializes this instruction as a store instruction with OpcodeLoad.
-func (i *Instruction) AsExtLoad(op Opcode, ptr Value, offset uint32, dst64bit bool) *Instruction {
- i.opcode = op
- i.v = ptr
- i.u1 = uint64(offset)
- if dst64bit {
- i.typ = TypeI64
- } else {
- i.typ = TypeI32
- }
- return i
-}
-
-// AsVZeroExtLoad initializes this instruction as a store instruction with OpcodeVExtLoad.
-func (i *Instruction) AsVZeroExtLoad(ptr Value, offset uint32, scalarType Type) *Instruction {
- i.opcode = OpcodeVZeroExtLoad
- i.v = ptr
- i.u1 = uint64(offset)
- i.u2 = uint64(scalarType)
- i.typ = TypeV128
- return i
-}
-
-// VZeroExtLoadData returns the operands for a load instruction. The returned `typ` is the scalar type of the load target.
-func (i *Instruction) VZeroExtLoadData() (ptr Value, offset uint32, typ Type) {
- return i.v, uint32(i.u1), Type(i.u2)
-}
-
-// AsLoadSplat initializes this instruction as a store instruction with OpcodeLoadSplat.
-func (i *Instruction) AsLoadSplat(ptr Value, offset uint32, lane VecLane) *Instruction {
- i.opcode = OpcodeLoadSplat
- i.v = ptr
- i.u1 = uint64(offset)
- i.u2 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// LoadData returns the operands for a load instruction.
-func (i *Instruction) LoadData() (ptr Value, offset uint32, typ Type) {
- return i.v, uint32(i.u1), i.typ
-}
-
-// LoadSplatData returns the operands for a load splat instruction.
-func (i *Instruction) LoadSplatData() (ptr Value, offset uint32, lane VecLane) {
- return i.v, uint32(i.u1), VecLane(i.u2)
-}
-
-// AsStore initializes this instruction as a store instruction with OpcodeStore.
-func (i *Instruction) AsStore(storeOp Opcode, value, ptr Value, offset uint32) *Instruction {
- i.opcode = storeOp
- i.v = value
- i.v2 = ptr
-
- var dstSize uint64
- switch storeOp {
- case OpcodeStore:
- dstSize = uint64(value.Type().Bits())
- case OpcodeIstore8:
- dstSize = 8
- case OpcodeIstore16:
- dstSize = 16
- case OpcodeIstore32:
- dstSize = 32
- default:
- panic("invalid store opcode" + storeOp.String())
- }
- i.u1 = uint64(offset) | dstSize<<32
- return i
-}
-
-// StoreData returns the operands for a store instruction.
-func (i *Instruction) StoreData() (value, ptr Value, offset uint32, storeSizeInBits byte) {
- return i.v, i.v2, uint32(i.u1), byte(i.u1 >> 32)
-}
-
-// AsIconst64 initializes this instruction as a 64-bit integer constant instruction with OpcodeIconst.
-func (i *Instruction) AsIconst64(v uint64) *Instruction {
- i.opcode = OpcodeIconst
- i.typ = TypeI64
- i.u1 = v
- return i
-}
-
-// AsIconst32 initializes this instruction as a 32-bit integer constant instruction with OpcodeIconst.
-func (i *Instruction) AsIconst32(v uint32) *Instruction {
- i.opcode = OpcodeIconst
- i.typ = TypeI32
- i.u1 = uint64(v)
- return i
-}
-
-// AsIadd initializes this instruction as an integer addition instruction with OpcodeIadd.
-func (i *Instruction) AsIadd(x, y Value) *Instruction {
- i.opcode = OpcodeIadd
- i.v = x
- i.v2 = y
- i.typ = x.Type()
- return i
-}
-
-// AsVIadd initializes this instruction as an integer addition instruction with OpcodeVIadd on a vector.
-func (i *Instruction) AsVIadd(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVIadd
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsWideningPairwiseDotProductS initializes this instruction as a lane-wise integer extended pairwise addition instruction
-// with OpcodeIaddPairwise on a vector.
-func (i *Instruction) AsWideningPairwiseDotProductS(x, y Value) *Instruction {
- i.opcode = OpcodeWideningPairwiseDotProductS
- i.v = x
- i.v2 = y
- i.typ = TypeV128
- return i
-}
-
-// AsExtIaddPairwise initializes this instruction as a lane-wise integer extended pairwise addition instruction
-// with OpcodeIaddPairwise on a vector.
-func (i *Instruction) AsExtIaddPairwise(x Value, srcLane VecLane, signed bool) *Instruction {
- i.opcode = OpcodeExtIaddPairwise
- i.v = x
- i.u1 = uint64(srcLane)
- if signed {
- i.u2 = 1
- }
- i.typ = TypeV128
- return i
-}
-
-// ExtIaddPairwiseData returns the operands for a lane-wise integer extended pairwise addition instruction.
-func (i *Instruction) ExtIaddPairwiseData() (x Value, srcLane VecLane, signed bool) {
- return i.v, VecLane(i.u1), i.u2 != 0
-}
-
-// AsVSaddSat initializes this instruction as a vector addition with saturation instruction with OpcodeVSaddSat on a vector.
-func (i *Instruction) AsVSaddSat(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVSaddSat
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVUaddSat initializes this instruction as a vector addition with saturation instruction with OpcodeVUaddSat on a vector.
-func (i *Instruction) AsVUaddSat(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVUaddSat
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVIsub initializes this instruction as an integer subtraction instruction with OpcodeVIsub on a vector.
-func (i *Instruction) AsVIsub(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVIsub
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVSsubSat initializes this instruction as a vector addition with saturation instruction with OpcodeVSsubSat on a vector.
-func (i *Instruction) AsVSsubSat(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVSsubSat
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVUsubSat initializes this instruction as a vector addition with saturation instruction with OpcodeVUsubSat on a vector.
-func (i *Instruction) AsVUsubSat(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVUsubSat
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVImin initializes this instruction as a signed integer min instruction with OpcodeVImin on a vector.
-func (i *Instruction) AsVImin(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVImin
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVUmin initializes this instruction as an unsigned integer min instruction with OpcodeVUmin on a vector.
-func (i *Instruction) AsVUmin(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVUmin
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVImax initializes this instruction as a signed integer max instruction with OpcodeVImax on a vector.
-func (i *Instruction) AsVImax(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVImax
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVUmax initializes this instruction as an unsigned integer max instruction with OpcodeVUmax on a vector.
-func (i *Instruction) AsVUmax(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVUmax
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVAvgRound initializes this instruction as an unsigned integer avg instruction, truncating to zero with OpcodeVAvgRound on a vector.
-func (i *Instruction) AsVAvgRound(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVAvgRound
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVImul initializes this instruction as an integer multiplication with OpcodeVImul on a vector.
-func (i *Instruction) AsVImul(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVImul
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsSqmulRoundSat initializes this instruction as a lane-wise saturating rounding multiplication
-// in Q15 format with OpcodeSqmulRoundSat on a vector.
-func (i *Instruction) AsSqmulRoundSat(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeSqmulRoundSat
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVIabs initializes this instruction as a vector absolute value with OpcodeVIabs.
-func (i *Instruction) AsVIabs(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVIabs
- i.v = x
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVIneg initializes this instruction as a vector negation with OpcodeVIneg.
-func (i *Instruction) AsVIneg(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVIneg
- i.v = x
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVIpopcnt initializes this instruction as a Population Count instruction with OpcodeVIpopcnt on a vector.
-func (i *Instruction) AsVIpopcnt(x Value, lane VecLane) *Instruction {
- if lane != VecLaneI8x16 {
- panic("Unsupported lane type " + lane.String())
- }
- i.opcode = OpcodeVIpopcnt
- i.v = x
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVSqrt initializes this instruction as a sqrt instruction with OpcodeVSqrt on a vector.
-func (i *Instruction) AsVSqrt(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVSqrt
- i.v = x
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVFabs initializes this instruction as a float abs instruction with OpcodeVFabs on a vector.
-func (i *Instruction) AsVFabs(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVFabs
- i.v = x
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVFneg initializes this instruction as a float neg instruction with OpcodeVFneg on a vector.
-func (i *Instruction) AsVFneg(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVFneg
- i.v = x
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVFmax initializes this instruction as a float max instruction with OpcodeVFmax on a vector.
-func (i *Instruction) AsVFmax(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVFmax
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVFmin initializes this instruction as a float min instruction with OpcodeVFmin on a vector.
-func (i *Instruction) AsVFmin(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVFmin
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVFadd initializes this instruction as a floating point add instruction with OpcodeVFadd on a vector.
-func (i *Instruction) AsVFadd(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVFadd
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVFsub initializes this instruction as a floating point subtraction instruction with OpcodeVFsub on a vector.
-func (i *Instruction) AsVFsub(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVFsub
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVFmul initializes this instruction as a floating point multiplication instruction with OpcodeVFmul on a vector.
-func (i *Instruction) AsVFmul(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVFmul
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVFdiv initializes this instruction as a floating point division instruction with OpcodeVFdiv on a vector.
-func (i *Instruction) AsVFdiv(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVFdiv
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsImul initializes this instruction as an integer addition instruction with OpcodeImul.
-func (i *Instruction) AsImul(x, y Value) *Instruction {
- i.opcode = OpcodeImul
- i.v = x
- i.v2 = y
- i.typ = x.Type()
- return i
-}
-
-func (i *Instruction) Insert(b Builder) *Instruction {
- b.InsertInstruction(i)
- return i
-}
-
-// AsIsub initializes this instruction as an integer subtraction instruction with OpcodeIsub.
-func (i *Instruction) AsIsub(x, y Value) *Instruction {
- i.opcode = OpcodeIsub
- i.v = x
- i.v2 = y
- i.typ = x.Type()
- return i
-}
-
-// AsIcmp initializes this instruction as an integer comparison instruction with OpcodeIcmp.
-func (i *Instruction) AsIcmp(x, y Value, c IntegerCmpCond) *Instruction {
- i.opcode = OpcodeIcmp
- i.v = x
- i.v2 = y
- i.u1 = uint64(c)
- i.typ = TypeI32
- return i
-}
-
-// AsFcmp initializes this instruction as an integer comparison instruction with OpcodeFcmp.
-func (i *Instruction) AsFcmp(x, y Value, c FloatCmpCond) {
- i.opcode = OpcodeFcmp
- i.v = x
- i.v2 = y
- i.u1 = uint64(c)
- i.typ = TypeI32
-}
-
-// AsVIcmp initializes this instruction as an integer vector comparison instruction with OpcodeVIcmp.
-func (i *Instruction) AsVIcmp(x, y Value, c IntegerCmpCond, lane VecLane) *Instruction {
- i.opcode = OpcodeVIcmp
- i.v = x
- i.v2 = y
- i.u1 = uint64(c)
- i.u2 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsVFcmp initializes this instruction as a float comparison instruction with OpcodeVFcmp on Vector.
-func (i *Instruction) AsVFcmp(x, y Value, c FloatCmpCond, lane VecLane) *Instruction {
- i.opcode = OpcodeVFcmp
- i.v = x
- i.v2 = y
- i.u1 = uint64(c)
- i.typ = TypeV128
- i.u2 = uint64(lane)
- return i
-}
-
-// AsVCeil initializes this instruction as an instruction with OpcodeCeil.
-func (i *Instruction) AsVCeil(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVCeil
- i.v = x
- i.typ = x.Type()
- i.u1 = uint64(lane)
- return i
-}
-
-// AsVFloor initializes this instruction as an instruction with OpcodeFloor.
-func (i *Instruction) AsVFloor(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVFloor
- i.v = x
- i.typ = x.Type()
- i.u1 = uint64(lane)
- return i
-}
-
-// AsVTrunc initializes this instruction as an instruction with OpcodeTrunc.
-func (i *Instruction) AsVTrunc(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVTrunc
- i.v = x
- i.typ = x.Type()
- i.u1 = uint64(lane)
- return i
-}
-
-// AsVNearest initializes this instruction as an instruction with OpcodeNearest.
-func (i *Instruction) AsVNearest(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVNearest
- i.v = x
- i.typ = x.Type()
- i.u1 = uint64(lane)
- return i
-}
-
-// AsVMaxPseudo initializes this instruction as an instruction with OpcodeVMaxPseudo.
-func (i *Instruction) AsVMaxPseudo(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVMaxPseudo
- i.typ = x.Type()
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- return i
-}
-
-// AsVMinPseudo initializes this instruction as an instruction with OpcodeVMinPseudo.
-func (i *Instruction) AsVMinPseudo(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVMinPseudo
- i.typ = x.Type()
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- return i
-}
-
-// AsSDiv initializes this instruction as an integer bitwise and instruction with OpcodeSdiv.
-func (i *Instruction) AsSDiv(x, y, ctx Value) *Instruction {
- i.opcode = OpcodeSdiv
- i.v = x
- i.v2 = y
- i.v3 = ctx
- i.typ = x.Type()
- return i
-}
-
-// AsUDiv initializes this instruction as an integer bitwise and instruction with OpcodeUdiv.
-func (i *Instruction) AsUDiv(x, y, ctx Value) *Instruction {
- i.opcode = OpcodeUdiv
- i.v = x
- i.v2 = y
- i.v3 = ctx
- i.typ = x.Type()
- return i
-}
-
-// AsSRem initializes this instruction as an integer bitwise and instruction with OpcodeSrem.
-func (i *Instruction) AsSRem(x, y, ctx Value) *Instruction {
- i.opcode = OpcodeSrem
- i.v = x
- i.v2 = y
- i.v3 = ctx
- i.typ = x.Type()
- return i
-}
-
-// AsURem initializes this instruction as an integer bitwise and instruction with OpcodeUrem.
-func (i *Instruction) AsURem(x, y, ctx Value) *Instruction {
- i.opcode = OpcodeUrem
- i.v = x
- i.v2 = y
- i.v3 = ctx
- i.typ = x.Type()
- return i
-}
-
-// AsBand initializes this instruction as an integer bitwise and instruction with OpcodeBand.
-func (i *Instruction) AsBand(x, amount Value) *Instruction {
- i.opcode = OpcodeBand
- i.v = x
- i.v2 = amount
- i.typ = x.Type()
- return i
-}
-
-// AsBor initializes this instruction as an integer bitwise or instruction with OpcodeBor.
-func (i *Instruction) AsBor(x, amount Value) {
- i.opcode = OpcodeBor
- i.v = x
- i.v2 = amount
- i.typ = x.Type()
-}
-
-// AsBxor initializes this instruction as an integer bitwise xor instruction with OpcodeBxor.
-func (i *Instruction) AsBxor(x, amount Value) {
- i.opcode = OpcodeBxor
- i.v = x
- i.v2 = amount
- i.typ = x.Type()
-}
-
-// AsIshl initializes this instruction as an integer shift left instruction with OpcodeIshl.
-func (i *Instruction) AsIshl(x, amount Value) *Instruction {
- i.opcode = OpcodeIshl
- i.v = x
- i.v2 = amount
- i.typ = x.Type()
- return i
-}
-
-// AsVIshl initializes this instruction as an integer shift left instruction with OpcodeVIshl on vector.
-func (i *Instruction) AsVIshl(x, amount Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVIshl
- i.v = x
- i.v2 = amount
- i.u1 = uint64(lane)
- i.typ = x.Type()
- return i
-}
-
-// AsUshr initializes this instruction as an integer unsigned shift right (logical shift right) instruction with OpcodeUshr.
-func (i *Instruction) AsUshr(x, amount Value) *Instruction {
- i.opcode = OpcodeUshr
- i.v = x
- i.v2 = amount
- i.typ = x.Type()
- return i
-}
-
-// AsVUshr initializes this instruction as an integer unsigned shift right (logical shift right) instruction with OpcodeVUshr on vector.
-func (i *Instruction) AsVUshr(x, amount Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVUshr
- i.v = x
- i.v2 = amount
- i.u1 = uint64(lane)
- i.typ = x.Type()
- return i
-}
-
-// AsSshr initializes this instruction as an integer signed shift right (arithmetic shift right) instruction with OpcodeSshr.
-func (i *Instruction) AsSshr(x, amount Value) *Instruction {
- i.opcode = OpcodeSshr
- i.v = x
- i.v2 = amount
- i.typ = x.Type()
- return i
-}
-
-// AsVSshr initializes this instruction as an integer signed shift right (arithmetic shift right) instruction with OpcodeVSshr on vector.
-func (i *Instruction) AsVSshr(x, amount Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVSshr
- i.v = x
- i.v2 = amount
- i.u1 = uint64(lane)
- i.typ = x.Type()
- return i
-}
-
-// AsExtractlane initializes this instruction as an extract lane instruction with OpcodeExtractlane on vector.
-func (i *Instruction) AsExtractlane(x Value, index byte, lane VecLane, signed bool) *Instruction {
- i.opcode = OpcodeExtractlane
- i.v = x
- // We do not have a field for signedness, but `index` is a byte,
- // so we just encode the flag in the high bits of `u1`.
- i.u1 = uint64(index)
- if signed {
- i.u1 = i.u1 | 1<<32
- }
- i.u2 = uint64(lane)
- switch lane {
- case VecLaneI8x16, VecLaneI16x8, VecLaneI32x4:
- i.typ = TypeI32
- case VecLaneI64x2:
- i.typ = TypeI64
- case VecLaneF32x4:
- i.typ = TypeF32
- case VecLaneF64x2:
- i.typ = TypeF64
- }
- return i
-}
-
-// AsInsertlane initializes this instruction as an insert lane instruction with OpcodeInsertlane on vector.
-func (i *Instruction) AsInsertlane(x, y Value, index byte, lane VecLane) *Instruction {
- i.opcode = OpcodeInsertlane
- i.v = x
- i.v2 = y
- i.u1 = uint64(index)
- i.u2 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsShuffle initializes this instruction as a shuffle instruction with OpcodeShuffle on vector.
-func (i *Instruction) AsShuffle(x, y Value, lane []byte) *Instruction {
- i.opcode = OpcodeShuffle
- i.v = x
- i.v2 = y
- // Encode the 16 bytes as 8 bytes in u1, and 8 bytes in u2.
- i.u1 = uint64(lane[7])<<56 | uint64(lane[6])<<48 | uint64(lane[5])<<40 | uint64(lane[4])<<32 | uint64(lane[3])<<24 | uint64(lane[2])<<16 | uint64(lane[1])<<8 | uint64(lane[0])
- i.u2 = uint64(lane[15])<<56 | uint64(lane[14])<<48 | uint64(lane[13])<<40 | uint64(lane[12])<<32 | uint64(lane[11])<<24 | uint64(lane[10])<<16 | uint64(lane[9])<<8 | uint64(lane[8])
- i.typ = TypeV128
- return i
-}
-
-// AsSwizzle initializes this instruction as an insert lane instruction with OpcodeSwizzle on vector.
-func (i *Instruction) AsSwizzle(x, y Value, lane VecLane) *Instruction {
- i.opcode = OpcodeSwizzle
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsSplat initializes this instruction as an insert lane instruction with OpcodeSplat on vector.
-func (i *Instruction) AsSplat(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeSplat
- i.v = x
- i.u1 = uint64(lane)
- i.typ = TypeV128
- return i
-}
-
-// AsRotl initializes this instruction as a word rotate left instruction with OpcodeRotl.
-func (i *Instruction) AsRotl(x, amount Value) {
- i.opcode = OpcodeRotl
- i.v = x
- i.v2 = amount
- i.typ = x.Type()
-}
-
-// AsRotr initializes this instruction as a word rotate right instruction with OpcodeRotr.
-func (i *Instruction) AsRotr(x, amount Value) {
- i.opcode = OpcodeRotr
- i.v = x
- i.v2 = amount
- i.typ = x.Type()
-}
-
-// IcmpData returns the operands and comparison condition of this integer comparison instruction.
-func (i *Instruction) IcmpData() (x, y Value, c IntegerCmpCond) {
- return i.v, i.v2, IntegerCmpCond(i.u1)
-}
-
-// FcmpData returns the operands and comparison condition of this floating-point comparison instruction.
-func (i *Instruction) FcmpData() (x, y Value, c FloatCmpCond) {
- return i.v, i.v2, FloatCmpCond(i.u1)
-}
-
-// VIcmpData returns the operands and comparison condition of this integer comparison instruction on vector.
-func (i *Instruction) VIcmpData() (x, y Value, c IntegerCmpCond, l VecLane) {
- return i.v, i.v2, IntegerCmpCond(i.u1), VecLane(i.u2)
-}
-
-// VFcmpData returns the operands and comparison condition of this float comparison instruction on vector.
-func (i *Instruction) VFcmpData() (x, y Value, c FloatCmpCond, l VecLane) {
- return i.v, i.v2, FloatCmpCond(i.u1), VecLane(i.u2)
-}
-
-// ExtractlaneData returns the operands and sign flag of Extractlane on vector.
-func (i *Instruction) ExtractlaneData() (x Value, index byte, signed bool, l VecLane) {
- x = i.v
- index = byte(0b00001111 & i.u1)
- signed = i.u1>>32 != 0
- l = VecLane(i.u2)
- return
-}
-
-// InsertlaneData returns the operands and sign flag of Insertlane on vector.
-func (i *Instruction) InsertlaneData() (x, y Value, index byte, l VecLane) {
- x = i.v
- y = i.v2
- index = byte(i.u1)
- l = VecLane(i.u2)
- return
-}
-
-// AsFadd initializes this instruction as a floating-point addition instruction with OpcodeFadd.
-func (i *Instruction) AsFadd(x, y Value) {
- i.opcode = OpcodeFadd
- i.v = x
- i.v2 = y
- i.typ = x.Type()
-}
-
-// AsFsub initializes this instruction as a floating-point subtraction instruction with OpcodeFsub.
-func (i *Instruction) AsFsub(x, y Value) {
- i.opcode = OpcodeFsub
- i.v = x
- i.v2 = y
- i.typ = x.Type()
-}
-
-// AsFmul initializes this instruction as a floating-point multiplication instruction with OpcodeFmul.
-func (i *Instruction) AsFmul(x, y Value) {
- i.opcode = OpcodeFmul
- i.v = x
- i.v2 = y
- i.typ = x.Type()
-}
-
-// AsFdiv initializes this instruction as a floating-point division instruction with OpcodeFdiv.
-func (i *Instruction) AsFdiv(x, y Value) {
- i.opcode = OpcodeFdiv
- i.v = x
- i.v2 = y
- i.typ = x.Type()
-}
-
-// AsFmin initializes this instruction to take the minimum of two floating-points with OpcodeFmin.
-func (i *Instruction) AsFmin(x, y Value) {
- i.opcode = OpcodeFmin
- i.v = x
- i.v2 = y
- i.typ = x.Type()
-}
-
-// AsFmax initializes this instruction to take the maximum of two floating-points with OpcodeFmax.
-func (i *Instruction) AsFmax(x, y Value) {
- i.opcode = OpcodeFmax
- i.v = x
- i.v2 = y
- i.typ = x.Type()
-}
-
-// AsF32const initializes this instruction as a 32-bit floating-point constant instruction with OpcodeF32const.
-func (i *Instruction) AsF32const(f float32) *Instruction {
- i.opcode = OpcodeF32const
- i.typ = TypeF64
- i.u1 = uint64(math.Float32bits(f))
- return i
-}
-
-// AsF64const initializes this instruction as a 64-bit floating-point constant instruction with OpcodeF64const.
-func (i *Instruction) AsF64const(f float64) *Instruction {
- i.opcode = OpcodeF64const
- i.typ = TypeF64
- i.u1 = math.Float64bits(f)
- return i
-}
-
-// AsVconst initializes this instruction as a vector constant instruction with OpcodeVconst.
-func (i *Instruction) AsVconst(lo, hi uint64) *Instruction {
- i.opcode = OpcodeVconst
- i.typ = TypeV128
- i.u1 = lo
- i.u2 = hi
- return i
-}
-
-// AsVbnot initializes this instruction as a vector negation instruction with OpcodeVbnot.
-func (i *Instruction) AsVbnot(v Value) *Instruction {
- i.opcode = OpcodeVbnot
- i.typ = TypeV128
- i.v = v
- return i
-}
-
-// AsVband initializes this instruction as an and vector instruction with OpcodeVband.
-func (i *Instruction) AsVband(x, y Value) *Instruction {
- i.opcode = OpcodeVband
- i.typ = TypeV128
- i.v = x
- i.v2 = y
- return i
-}
-
-// AsVbor initializes this instruction as an or vector instruction with OpcodeVbor.
-func (i *Instruction) AsVbor(x, y Value) *Instruction {
- i.opcode = OpcodeVbor
- i.typ = TypeV128
- i.v = x
- i.v2 = y
- return i
-}
-
-// AsVbxor initializes this instruction as a xor vector instruction with OpcodeVbxor.
-func (i *Instruction) AsVbxor(x, y Value) *Instruction {
- i.opcode = OpcodeVbxor
- i.typ = TypeV128
- i.v = x
- i.v2 = y
- return i
-}
-
-// AsVbandnot initializes this instruction as an and-not vector instruction with OpcodeVbandnot.
-func (i *Instruction) AsVbandnot(x, y Value) *Instruction {
- i.opcode = OpcodeVbandnot
- i.typ = TypeV128
- i.v = x
- i.v2 = y
- return i
-}
-
-// AsVbitselect initializes this instruction as a bit select vector instruction with OpcodeVbitselect.
-func (i *Instruction) AsVbitselect(c, x, y Value) *Instruction {
- i.opcode = OpcodeVbitselect
- i.typ = TypeV128
- i.v = c
- i.v2 = x
- i.v3 = y
- return i
-}
-
-// AsVanyTrue initializes this instruction as an anyTrue vector instruction with OpcodeVanyTrue.
-func (i *Instruction) AsVanyTrue(x Value) *Instruction {
- i.opcode = OpcodeVanyTrue
- i.typ = TypeI32
- i.v = x
- return i
-}
-
-// AsVallTrue initializes this instruction as an allTrue vector instruction with OpcodeVallTrue.
-func (i *Instruction) AsVallTrue(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVallTrue
- i.typ = TypeI32
- i.v = x
- i.u1 = uint64(lane)
- return i
-}
-
-// AsVhighBits initializes this instruction as a highBits vector instruction with OpcodeVhighBits.
-func (i *Instruction) AsVhighBits(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeVhighBits
- i.typ = TypeI32
- i.v = x
- i.u1 = uint64(lane)
- return i
-}
-
-// VconstData returns the operands of this vector constant instruction.
-func (i *Instruction) VconstData() (lo, hi uint64) {
- return i.u1, i.u2
-}
-
-// AsReturn initializes this instruction as a return instruction with OpcodeReturn.
-func (i *Instruction) AsReturn(vs wazevoapi.VarLength[Value]) *Instruction {
- i.opcode = OpcodeReturn
- i.vs = vs
- return i
-}
-
-// AsIreduce initializes this instruction as a reduction instruction with OpcodeIreduce.
-func (i *Instruction) AsIreduce(v Value, dstType Type) *Instruction {
- i.opcode = OpcodeIreduce
- i.v = v
- i.typ = dstType
- return i
-}
-
-// AsWiden initializes this instruction as a signed or unsigned widen instruction
-// on low half or high half of the given vector with OpcodeSwidenLow, OpcodeUwidenLow, OpcodeSwidenHigh, OpcodeUwidenHigh.
-func (i *Instruction) AsWiden(v Value, lane VecLane, signed, low bool) *Instruction {
- switch {
- case signed && low:
- i.opcode = OpcodeSwidenLow
- case !signed && low:
- i.opcode = OpcodeUwidenLow
- case signed && !low:
- i.opcode = OpcodeSwidenHigh
- case !signed && !low:
- i.opcode = OpcodeUwidenHigh
- }
- i.v = v
- i.u1 = uint64(lane)
- return i
-}
-
-// AsAtomicLoad initializes this instruction as an atomic load.
-// The size is in bytes and must be 1, 2, 4, or 8.
-func (i *Instruction) AsAtomicLoad(addr Value, size uint64, typ Type) *Instruction {
- i.opcode = OpcodeAtomicLoad
- i.u1 = size
- i.v = addr
- i.typ = typ
- return i
-}
-
-// AsAtomicLoad initializes this instruction as an atomic store.
-// The size is in bytes and must be 1, 2, 4, or 8.
-func (i *Instruction) AsAtomicStore(addr, val Value, size uint64) *Instruction {
- i.opcode = OpcodeAtomicStore
- i.u1 = size
- i.v = addr
- i.v2 = val
- i.typ = val.Type()
- return i
-}
-
-// AsAtomicRmw initializes this instruction as an atomic read-modify-write.
-// The size is in bytes and must be 1, 2, 4, or 8.
-func (i *Instruction) AsAtomicRmw(op AtomicRmwOp, addr, val Value, size uint64) *Instruction {
- i.opcode = OpcodeAtomicRmw
- i.u1 = uint64(op)
- i.u2 = size
- i.v = addr
- i.v2 = val
- i.typ = val.Type()
- return i
-}
-
-// AsAtomicCas initializes this instruction as an atomic compare-and-swap.
-// The size is in bytes and must be 1, 2, 4, or 8.
-func (i *Instruction) AsAtomicCas(addr, exp, repl Value, size uint64) *Instruction {
- i.opcode = OpcodeAtomicCas
- i.u1 = size
- i.v = addr
- i.v2 = exp
- i.v3 = repl
- i.typ = repl.Type()
- return i
-}
-
-// AsFence initializes this instruction as a memory fence.
-// A single byte immediate may be used to indicate fence ordering in the future
-// but is currently always 0 and ignored.
-func (i *Instruction) AsFence(order byte) *Instruction {
- i.opcode = OpcodeFence
- i.u1 = uint64(order)
- return i
-}
-
-// AtomicRmwData returns the data for this atomic read-modify-write instruction.
-func (i *Instruction) AtomicRmwData() (op AtomicRmwOp, size uint64) {
- return AtomicRmwOp(i.u1), i.u2
-}
-
-// AtomicTargetSize returns the target memory size of the atomic instruction.
-func (i *Instruction) AtomicTargetSize() (size uint64) {
- return i.u1
-}
-
-// ReturnVals returns the return values of OpcodeReturn.
-func (i *Instruction) ReturnVals() []Value {
- return i.vs.View()
-}
-
-// AsExitWithCode initializes this instruction as a trap instruction with OpcodeExitWithCode.
-func (i *Instruction) AsExitWithCode(ctx Value, code wazevoapi.ExitCode) {
- i.opcode = OpcodeExitWithCode
- i.v = ctx
- i.u1 = uint64(code)
-}
-
-// AsExitIfTrueWithCode initializes this instruction as a trap instruction with OpcodeExitIfTrueWithCode.
-func (i *Instruction) AsExitIfTrueWithCode(ctx, c Value, code wazevoapi.ExitCode) *Instruction {
- i.opcode = OpcodeExitIfTrueWithCode
- i.v = ctx
- i.v2 = c
- i.u1 = uint64(code)
- return i
-}
-
-// ExitWithCodeData returns the context and exit code of OpcodeExitWithCode.
-func (i *Instruction) ExitWithCodeData() (ctx Value, code wazevoapi.ExitCode) {
- return i.v, wazevoapi.ExitCode(i.u1)
-}
-
-// ExitIfTrueWithCodeData returns the context and exit code of OpcodeExitWithCode.
-func (i *Instruction) ExitIfTrueWithCodeData() (ctx, c Value, code wazevoapi.ExitCode) {
- return i.v, i.v2, wazevoapi.ExitCode(i.u1)
-}
-
-// InvertBrx inverts either OpcodeBrz or OpcodeBrnz to the other.
-func (i *Instruction) InvertBrx() {
- switch i.opcode {
- case OpcodeBrz:
- i.opcode = OpcodeBrnz
- case OpcodeBrnz:
- i.opcode = OpcodeBrz
- default:
- panic("BUG")
- }
-}
-
-// BranchData returns the branch data for this instruction necessary for backends.
-func (i *Instruction) BranchData() (condVal Value, blockArgs []Value, target BasicBlockID) {
- switch i.opcode {
- case OpcodeJump:
- condVal = ValueInvalid
- case OpcodeBrz, OpcodeBrnz:
- condVal = i.v
- default:
- panic("BUG")
- }
- blockArgs = i.vs.View()
- target = BasicBlockID(i.rValue)
- return
-}
-
-// BrTableData returns the branch table data for this instruction necessary for backends.
-func (i *Instruction) BrTableData() (index Value, targets Values) {
- if i.opcode != OpcodeBrTable {
- panic("BUG: BrTableData only available for OpcodeBrTable")
- }
- index = i.v
- targets = i.rValues
- return
-}
-
-// AsJump initializes this instruction as a jump instruction with OpcodeJump.
-func (i *Instruction) AsJump(vs Values, target BasicBlock) *Instruction {
- i.opcode = OpcodeJump
- i.vs = vs
- i.rValue = Value(target.ID())
- return i
-}
-
-// IsFallthroughJump returns true if this instruction is a fallthrough jump.
-func (i *Instruction) IsFallthroughJump() bool {
- if i.opcode != OpcodeJump {
- panic("BUG: IsFallthrough only available for OpcodeJump")
- }
- return i.opcode == OpcodeJump && i.u1 != 0
-}
-
-// AsFallthroughJump marks this instruction as a fallthrough jump.
-func (i *Instruction) AsFallthroughJump() {
- if i.opcode != OpcodeJump {
- panic("BUG: AsFallthroughJump only available for OpcodeJump")
- }
- i.u1 = 1
-}
-
-// AsBrz initializes this instruction as a branch-if-zero instruction with OpcodeBrz.
-func (i *Instruction) AsBrz(v Value, args Values, target BasicBlock) {
- i.opcode = OpcodeBrz
- i.v = v
- i.vs = args
- i.rValue = Value(target.ID())
-}
-
-// AsBrnz initializes this instruction as a branch-if-not-zero instruction with OpcodeBrnz.
-func (i *Instruction) AsBrnz(v Value, args Values, target BasicBlock) *Instruction {
- i.opcode = OpcodeBrnz
- i.v = v
- i.vs = args
- i.rValue = Value(target.ID())
- return i
-}
-
-// AsBrTable initializes this instruction as a branch-table instruction with OpcodeBrTable.
-// 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.rValues = targets
-}
-
-// AsCall initializes this instruction as a call instruction with OpcodeCall.
-func (i *Instruction) AsCall(ref FuncRef, sig *Signature, args Values) {
- i.opcode = OpcodeCall
- i.u1 = uint64(ref)
- i.vs = args
- i.u2 = uint64(sig.ID)
- sig.used = true
-}
-
-// CallData returns the call data for this instruction necessary for backends.
-func (i *Instruction) CallData() (ref FuncRef, sigID SignatureID, args []Value) {
- if i.opcode != OpcodeCall {
- panic("BUG: CallData only available for OpcodeCall")
- }
- ref = FuncRef(i.u1)
- sigID = SignatureID(i.u2)
- args = i.vs.View()
- return
-}
-
-// AsCallIndirect initializes this instruction as a call-indirect instruction with OpcodeCallIndirect.
-func (i *Instruction) AsCallIndirect(funcPtr Value, sig *Signature, args Values) *Instruction {
- i.opcode = OpcodeCallIndirect
- i.typ = TypeF64
- i.vs = args
- i.v = funcPtr
- i.u1 = uint64(sig.ID)
- sig.used = true
- return i
-}
-
-// AsCallGoRuntimeMemmove is the same as AsCallIndirect, but with a special flag set to indicate that it is a call to the Go runtime memmove function.
-func (i *Instruction) AsCallGoRuntimeMemmove(funcPtr Value, sig *Signature, args Values) *Instruction {
- i.AsCallIndirect(funcPtr, sig, args)
- i.u2 = 1
- return i
-}
-
-// CallIndirectData returns the call indirect data for this instruction necessary for backends.
-func (i *Instruction) CallIndirectData() (funcPtr Value, sigID SignatureID, args []Value, isGoMemmove bool) {
- if i.opcode != OpcodeCallIndirect {
- panic("BUG: CallIndirectData only available for OpcodeCallIndirect")
- }
- funcPtr = i.v
- sigID = SignatureID(i.u1)
- args = i.vs.View()
- isGoMemmove = i.u2 == 1
- return
-}
-
-// AsClz initializes this instruction as a Count Leading Zeroes instruction with OpcodeClz.
-func (i *Instruction) AsClz(x Value) {
- i.opcode = OpcodeClz
- i.v = x
- i.typ = x.Type()
-}
-
-// AsCtz initializes this instruction as a Count Trailing Zeroes instruction with OpcodeCtz.
-func (i *Instruction) AsCtz(x Value) {
- i.opcode = OpcodeCtz
- i.v = x
- i.typ = x.Type()
-}
-
-// AsPopcnt initializes this instruction as a Population Count instruction with OpcodePopcnt.
-func (i *Instruction) AsPopcnt(x Value) {
- i.opcode = OpcodePopcnt
- i.v = x
- i.typ = x.Type()
-}
-
-// AsFneg initializes this instruction as an instruction with OpcodeFneg.
-func (i *Instruction) AsFneg(x Value) *Instruction {
- i.opcode = OpcodeFneg
- i.v = x
- i.typ = x.Type()
- return i
-}
-
-// AsSqrt initializes this instruction as an instruction with OpcodeSqrt.
-func (i *Instruction) AsSqrt(x Value) *Instruction {
- i.opcode = OpcodeSqrt
- i.v = x
- i.typ = x.Type()
- return i
-}
-
-// AsFabs initializes this instruction as an instruction with OpcodeFabs.
-func (i *Instruction) AsFabs(x Value) *Instruction {
- i.opcode = OpcodeFabs
- i.v = x
- i.typ = x.Type()
- return i
-}
-
-// AsFcopysign initializes this instruction as an instruction with OpcodeFcopysign.
-func (i *Instruction) AsFcopysign(x, y Value) *Instruction {
- i.opcode = OpcodeFcopysign
- i.v = x
- i.v2 = y
- i.typ = x.Type()
- return i
-}
-
-// AsCeil initializes this instruction as an instruction with OpcodeCeil.
-func (i *Instruction) AsCeil(x Value) *Instruction {
- i.opcode = OpcodeCeil
- i.v = x
- i.typ = x.Type()
- return i
-}
-
-// AsFloor initializes this instruction as an instruction with OpcodeFloor.
-func (i *Instruction) AsFloor(x Value) *Instruction {
- i.opcode = OpcodeFloor
- i.v = x
- i.typ = x.Type()
- return i
-}
-
-// AsTrunc initializes this instruction as an instruction with OpcodeTrunc.
-func (i *Instruction) AsTrunc(x Value) *Instruction {
- i.opcode = OpcodeTrunc
- i.v = x
- i.typ = x.Type()
- return i
-}
-
-// AsNearest initializes this instruction as an instruction with OpcodeNearest.
-func (i *Instruction) AsNearest(x Value) *Instruction {
- i.opcode = OpcodeNearest
- i.v = x
- i.typ = x.Type()
- return i
-}
-
-// AsBitcast initializes this instruction as an instruction with OpcodeBitcast.
-func (i *Instruction) AsBitcast(x Value, dstType Type) *Instruction {
- i.opcode = OpcodeBitcast
- i.v = x
- i.typ = dstType
- return i
-}
-
-// BitcastData returns the operands for a bitcast instruction.
-func (i *Instruction) BitcastData() (x Value, dstType Type) {
- return i.v, i.typ
-}
-
-// AsFdemote initializes this instruction as an instruction with OpcodeFdemote.
-func (i *Instruction) AsFdemote(x Value) {
- i.opcode = OpcodeFdemote
- i.v = x
- i.typ = TypeF32
-}
-
-// AsFpromote initializes this instruction as an instruction with OpcodeFpromote.
-func (i *Instruction) AsFpromote(x Value) {
- i.opcode = OpcodeFpromote
- i.v = x
- i.typ = TypeF64
-}
-
-// AsFcvtFromInt initializes this instruction as an instruction with either OpcodeFcvtFromUint or OpcodeFcvtFromSint
-func (i *Instruction) AsFcvtFromInt(x Value, signed bool, dst64bit bool) *Instruction {
- if signed {
- i.opcode = OpcodeFcvtFromSint
- } else {
- i.opcode = OpcodeFcvtFromUint
- }
- i.v = x
- if dst64bit {
- i.typ = TypeF64
- } else {
- i.typ = TypeF32
- }
- return i
-}
-
-// AsFcvtToInt initializes this instruction as an instruction with either OpcodeFcvtToUint or OpcodeFcvtToSint
-func (i *Instruction) AsFcvtToInt(x, ctx Value, signed bool, dst64bit bool, sat bool) *Instruction {
- switch {
- case signed && !sat:
- i.opcode = OpcodeFcvtToSint
- case !signed && !sat:
- i.opcode = OpcodeFcvtToUint
- case signed && sat:
- i.opcode = OpcodeFcvtToSintSat
- case !signed && sat:
- i.opcode = OpcodeFcvtToUintSat
- }
- i.v = x
- i.v2 = ctx
- if dst64bit {
- i.typ = TypeI64
- } else {
- i.typ = TypeI32
- }
- return i
-}
-
-// AsVFcvtToIntSat initializes this instruction as an instruction with either OpcodeVFcvtToSintSat or OpcodeVFcvtToUintSat
-func (i *Instruction) AsVFcvtToIntSat(x Value, lane VecLane, signed bool) *Instruction {
- if signed {
- i.opcode = OpcodeVFcvtToSintSat
- } else {
- i.opcode = OpcodeVFcvtToUintSat
- }
- i.v = x
- i.u1 = uint64(lane)
- return i
-}
-
-// AsVFcvtFromInt initializes this instruction as an instruction with either OpcodeVFcvtToSintSat or OpcodeVFcvtToUintSat
-func (i *Instruction) AsVFcvtFromInt(x Value, lane VecLane, signed bool) *Instruction {
- if signed {
- i.opcode = OpcodeVFcvtFromSint
- } else {
- i.opcode = OpcodeVFcvtFromUint
- }
- i.v = x
- i.u1 = uint64(lane)
- return i
-}
-
-// AsNarrow initializes this instruction as an instruction with either OpcodeSnarrow or OpcodeUnarrow
-func (i *Instruction) AsNarrow(x, y Value, lane VecLane, signed bool) *Instruction {
- if signed {
- i.opcode = OpcodeSnarrow
- } else {
- i.opcode = OpcodeUnarrow
- }
- i.v = x
- i.v2 = y
- i.u1 = uint64(lane)
- return i
-}
-
-// AsFvpromoteLow initializes this instruction as an instruction with OpcodeFvpromoteLow
-func (i *Instruction) AsFvpromoteLow(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeFvpromoteLow
- i.v = x
- i.u1 = uint64(lane)
- return i
-}
-
-// AsFvdemote initializes this instruction as an instruction with OpcodeFvdemote
-func (i *Instruction) AsFvdemote(x Value, lane VecLane) *Instruction {
- i.opcode = OpcodeFvdemote
- i.v = x
- i.u1 = uint64(lane)
- return i
-}
-
-// AsSExtend initializes this instruction as a sign extension instruction with OpcodeSExtend.
-func (i *Instruction) AsSExtend(v Value, from, to byte) *Instruction {
- i.opcode = OpcodeSExtend
- i.v = v
- i.u1 = uint64(from)<<8 | uint64(to)
- if to == 64 {
- i.typ = TypeI64
- } else {
- i.typ = TypeI32
- }
- return i
-}
-
-// AsUExtend initializes this instruction as an unsigned extension instruction with OpcodeUExtend.
-func (i *Instruction) AsUExtend(v Value, from, to byte) *Instruction {
- i.opcode = OpcodeUExtend
- i.v = v
- i.u1 = uint64(from)<<8 | uint64(to)
- if to == 64 {
- i.typ = TypeI64
- } else {
- i.typ = TypeI32
- }
- return i
-}
-
-func (i *Instruction) ExtendData() (from, to byte, signed bool) {
- if i.opcode != OpcodeSExtend && i.opcode != OpcodeUExtend {
- panic("BUG: ExtendData only available for OpcodeSExtend and OpcodeUExtend")
- }
- from = byte(i.u1 >> 8)
- to = byte(i.u1)
- signed = i.opcode == OpcodeSExtend
- return
-}
-
-// AsSelect initializes this instruction as an unsigned extension instruction with OpcodeSelect.
-func (i *Instruction) AsSelect(c, x, y Value) *Instruction {
- i.opcode = OpcodeSelect
- i.v = c
- i.v2 = x
- i.v3 = y
- i.typ = x.Type()
- return i
-}
-
-// SelectData returns the select data for this instruction necessary for backends.
-func (i *Instruction) SelectData() (c, x, y Value) {
- c = i.v
- x = i.v2
- y = i.v3
- return
-}
-
-// ExtendFromToBits returns the from and to bit size for the extension instruction.
-func (i *Instruction) ExtendFromToBits() (from, to byte) {
- from = byte(i.u1 >> 8)
- to = byte(i.u1)
- return
-}
-
-// Format returns a string representation of this instruction with the given builder.
-// For debugging purposes only.
-func (i *Instruction) Format(b Builder) string {
- var instSuffix string
- switch i.opcode {
- case OpcodeExitWithCode:
- instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), wazevoapi.ExitCode(i.u1))
- case OpcodeExitIfTrueWithCode:
- instSuffix = fmt.Sprintf(" %s, %s, %s", i.v2.Format(b), i.v.Format(b), wazevoapi.ExitCode(i.u1))
- case OpcodeIadd, OpcodeIsub, OpcodeImul, OpcodeFadd, OpcodeFsub, OpcodeFmin, OpcodeFmax, OpcodeFdiv, OpcodeFmul:
- instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), i.v2.Format(b))
- case OpcodeIcmp:
- instSuffix = fmt.Sprintf(" %s, %s, %s", IntegerCmpCond(i.u1), i.v.Format(b), i.v2.Format(b))
- case OpcodeFcmp:
- instSuffix = fmt.Sprintf(" %s, %s, %s", FloatCmpCond(i.u1), i.v.Format(b), i.v2.Format(b))
- case OpcodeSExtend, OpcodeUExtend:
- instSuffix = fmt.Sprintf(" %s, %d->%d", i.v.Format(b), i.u1>>8, i.u1&0xff)
- case OpcodeCall, OpcodeCallIndirect:
- view := i.vs.View()
- vs := make([]string, len(view))
- for idx := range vs {
- vs[idx] = view[idx].Format(b)
- }
- if i.opcode == OpcodeCallIndirect {
- instSuffix = fmt.Sprintf(" %s:%s, %s", i.v.Format(b), SignatureID(i.u1), strings.Join(vs, ", "))
- } else {
- instSuffix = fmt.Sprintf(" %s:%s, %s", FuncRef(i.u1), SignatureID(i.u2), strings.Join(vs, ", "))
- }
- case OpcodeStore, OpcodeIstore8, OpcodeIstore16, OpcodeIstore32:
- instSuffix = fmt.Sprintf(" %s, %s, %#x", i.v.Format(b), i.v2.Format(b), uint32(i.u1))
- case OpcodeLoad, OpcodeVZeroExtLoad:
- instSuffix = fmt.Sprintf(" %s, %#x", i.v.Format(b), int32(i.u1))
- case OpcodeLoadSplat:
- instSuffix = fmt.Sprintf(".%s %s, %#x", VecLane(i.u2), i.v.Format(b), int32(i.u1))
- case OpcodeUload8, OpcodeUload16, OpcodeUload32, OpcodeSload8, OpcodeSload16, OpcodeSload32:
- instSuffix = fmt.Sprintf(" %s, %#x", i.v.Format(b), int32(i.u1))
- case OpcodeSelect, OpcodeVbitselect:
- instSuffix = fmt.Sprintf(" %s, %s, %s", i.v.Format(b), i.v2.Format(b), i.v3.Format(b))
- case OpcodeIconst:
- switch i.typ {
- case TypeI32:
- instSuffix = fmt.Sprintf("_32 %#x", uint32(i.u1))
- case TypeI64:
- instSuffix = fmt.Sprintf("_64 %#x", i.u1)
- }
- case OpcodeVconst:
- instSuffix = fmt.Sprintf(" %016x %016x", i.u1, i.u2)
- case OpcodeF32const:
- instSuffix = fmt.Sprintf(" %f", math.Float32frombits(uint32(i.u1)))
- case OpcodeF64const:
- instSuffix = fmt.Sprintf(" %f", math.Float64frombits(i.u1))
- case OpcodeReturn:
- view := i.vs.View()
- if len(view) == 0 {
- break
- }
- vs := make([]string, len(view))
- for idx := range vs {
- vs[idx] = view[idx].Format(b)
- }
- instSuffix = fmt.Sprintf(" %s", strings.Join(vs, ", "))
- case OpcodeJump:
- view := i.vs.View()
- vs := make([]string, len(view)+1)
- if i.IsFallthroughJump() {
- vs[0] = " fallthrough"
- } else {
- blockId := BasicBlockID(i.rValue)
- vs[0] = " " + b.BasicBlock(blockId).Name()
- }
- for idx := range view {
- vs[idx+1] = view[idx].Format(b)
- }
-
- instSuffix = strings.Join(vs, ", ")
- case OpcodeBrz, OpcodeBrnz:
- view := i.vs.View()
- vs := make([]string, len(view)+2)
- vs[0] = " " + i.v.Format(b)
- blockId := BasicBlockID(i.rValue)
- vs[1] = b.BasicBlock(blockId).Name()
- for idx := range view {
- vs[idx+2] = view[idx].Format(b)
- }
- instSuffix = strings.Join(vs, ", ")
- case OpcodeBrTable:
- // `BrTable index, [label1, label2, ... labelN]`
- instSuffix = fmt.Sprintf(" %s", i.v.Format(b))
- instSuffix += ", ["
- for i, target := range i.rValues.View() {
- blk := b.BasicBlock(BasicBlockID(target))
- if i == 0 {
- instSuffix += blk.Name()
- } else {
- instSuffix += ", " + blk.Name()
- }
- }
- instSuffix += "]"
- case OpcodeBand, OpcodeBor, OpcodeBxor, OpcodeRotr, OpcodeRotl, OpcodeIshl, OpcodeSshr, OpcodeUshr,
- OpcodeSdiv, OpcodeUdiv, OpcodeFcopysign, OpcodeSrem, OpcodeUrem,
- OpcodeVbnot, OpcodeVbxor, OpcodeVbor, OpcodeVband, OpcodeVbandnot, OpcodeVIcmp, OpcodeVFcmp:
- instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), i.v2.Format(b))
- case OpcodeUndefined:
- case OpcodeClz, OpcodeCtz, OpcodePopcnt, OpcodeFneg, OpcodeFcvtToSint, OpcodeFcvtToUint, OpcodeFcvtFromSint,
- OpcodeFcvtFromUint, OpcodeFcvtToSintSat, OpcodeFcvtToUintSat, OpcodeFdemote, OpcodeFpromote, OpcodeIreduce, OpcodeBitcast, OpcodeSqrt, OpcodeFabs,
- OpcodeCeil, OpcodeFloor, OpcodeTrunc, OpcodeNearest:
- instSuffix = " " + i.v.Format(b)
- case OpcodeVIadd, OpcodeExtIaddPairwise, OpcodeVSaddSat, OpcodeVUaddSat, OpcodeVIsub, OpcodeVSsubSat, OpcodeVUsubSat,
- OpcodeVImin, OpcodeVUmin, OpcodeVImax, OpcodeVUmax, OpcodeVImul, OpcodeVAvgRound,
- OpcodeVFadd, OpcodeVFsub, OpcodeVFmul, OpcodeVFdiv,
- OpcodeVIshl, OpcodeVSshr, OpcodeVUshr,
- OpcodeVFmin, OpcodeVFmax, OpcodeVMinPseudo, OpcodeVMaxPseudo,
- OpcodeSnarrow, OpcodeUnarrow, OpcodeSwizzle, OpcodeSqmulRoundSat:
- instSuffix = fmt.Sprintf(".%s %s, %s", VecLane(i.u1), i.v.Format(b), i.v2.Format(b))
- case OpcodeVIabs, OpcodeVIneg, OpcodeVIpopcnt, OpcodeVhighBits, OpcodeVallTrue, OpcodeVanyTrue,
- OpcodeVFabs, OpcodeVFneg, OpcodeVSqrt, OpcodeVCeil, OpcodeVFloor, OpcodeVTrunc, OpcodeVNearest,
- OpcodeVFcvtToUintSat, OpcodeVFcvtToSintSat, OpcodeVFcvtFromUint, OpcodeVFcvtFromSint,
- OpcodeFvpromoteLow, OpcodeFvdemote, OpcodeSwidenLow, OpcodeUwidenLow, OpcodeSwidenHigh, OpcodeUwidenHigh,
- OpcodeSplat:
- instSuffix = fmt.Sprintf(".%s %s", VecLane(i.u1), i.v.Format(b))
- case OpcodeExtractlane:
- var signedness string
- if i.u1 != 0 {
- signedness = "signed"
- } else {
- signedness = "unsigned"
- }
- instSuffix = fmt.Sprintf(".%s %d, %s (%s)", VecLane(i.u2), 0x0000FFFF&i.u1, i.v.Format(b), signedness)
- case OpcodeInsertlane:
- instSuffix = fmt.Sprintf(".%s %d, %s, %s", VecLane(i.u2), i.u1, i.v.Format(b), i.v2.Format(b))
- case OpcodeShuffle:
- lanes := make([]byte, 16)
- for idx := 0; idx < 8; idx++ {
- lanes[idx] = byte(i.u1 >> (8 * idx))
- }
- for idx := 0; idx < 8; idx++ {
- lanes[idx+8] = byte(i.u2 >> (8 * idx))
- }
- // Prints Shuffle.[0 1 2 3 4 5 6 7 ...] v2, v3
- instSuffix = fmt.Sprintf(".%v %s, %s", lanes, i.v.Format(b), i.v2.Format(b))
- case OpcodeAtomicRmw:
- instSuffix = fmt.Sprintf(" %s_%d, %s, %s", AtomicRmwOp(i.u1), 8*i.u2, i.v.Format(b), i.v2.Format(b))
- case OpcodeAtomicLoad:
- instSuffix = fmt.Sprintf("_%d, %s", 8*i.u1, i.v.Format(b))
- case OpcodeAtomicStore:
- instSuffix = fmt.Sprintf("_%d, %s, %s", 8*i.u1, i.v.Format(b), i.v2.Format(b))
- case OpcodeAtomicCas:
- instSuffix = fmt.Sprintf("_%d, %s, %s, %s", 8*i.u1, i.v.Format(b), i.v2.Format(b), i.v3.Format(b))
- case OpcodeFence:
- instSuffix = fmt.Sprintf(" %d", i.u1)
- case OpcodeWideningPairwiseDotProductS:
- instSuffix = fmt.Sprintf(" %s, %s", i.v.Format(b), i.v2.Format(b))
- default:
- panic(fmt.Sprintf("TODO: format for %s", i.opcode))
- }
-
- instr := i.opcode.String() + instSuffix
-
- var rvs []string
- r1, rs := i.Returns()
- if r1.Valid() {
- rvs = append(rvs, r1.formatWithType(b))
- }
-
- for _, v := range rs {
- rvs = append(rvs, v.formatWithType(b))
- }
-
- if len(rvs) > 0 {
- return fmt.Sprintf("%s = %s", strings.Join(rvs, ", "), instr)
- } else {
- return instr
- }
-}
-
-// addArgumentBranchInst adds an argument to this instruction.
-func (i *Instruction) addArgumentBranchInst(b *builder, v Value) {
- switch i.opcode {
- case OpcodeJump, OpcodeBrz, OpcodeBrnz:
- i.vs = i.vs.Append(&b.varLengthPool, v)
- default:
- panic("BUG: " + i.opcode.String())
- }
-}
-
-// Constant returns true if this instruction is a constant instruction.
-func (i *Instruction) Constant() bool {
- switch i.opcode {
- case OpcodeIconst, OpcodeF32const, OpcodeF64const:
- return true
- }
- return false
-}
-
-// ConstantVal returns the constant value of this instruction.
-// How to interpret the return value depends on the opcode.
-func (i *Instruction) ConstantVal() (ret uint64) {
- switch i.opcode {
- case OpcodeIconst, OpcodeF32const, OpcodeF64const:
- ret = i.u1
- default:
- panic("TODO")
- }
- return
-}
-
-// String implements fmt.Stringer.
-func (o Opcode) String() (ret string) {
- switch o {
- case OpcodeInvalid:
- return "invalid"
- case OpcodeUndefined:
- return "Undefined"
- case OpcodeJump:
- return "Jump"
- case OpcodeBrz:
- return "Brz"
- case OpcodeBrnz:
- return "Brnz"
- case OpcodeBrTable:
- return "BrTable"
- case OpcodeExitWithCode:
- return "Exit"
- case OpcodeExitIfTrueWithCode:
- return "ExitIfTrue"
- case OpcodeReturn:
- return "Return"
- case OpcodeCall:
- return "Call"
- case OpcodeCallIndirect:
- return "CallIndirect"
- case OpcodeSplat:
- return "Splat"
- case OpcodeSwizzle:
- return "Swizzle"
- case OpcodeInsertlane:
- return "Insertlane"
- case OpcodeExtractlane:
- return "Extractlane"
- case OpcodeLoad:
- return "Load"
- case OpcodeLoadSplat:
- return "LoadSplat"
- case OpcodeStore:
- return "Store"
- case OpcodeUload8:
- return "Uload8"
- case OpcodeSload8:
- return "Sload8"
- case OpcodeIstore8:
- return "Istore8"
- case OpcodeUload16:
- return "Uload16"
- case OpcodeSload16:
- return "Sload16"
- case OpcodeIstore16:
- return "Istore16"
- case OpcodeUload32:
- return "Uload32"
- case OpcodeSload32:
- return "Sload32"
- case OpcodeIstore32:
- return "Istore32"
- case OpcodeIconst:
- return "Iconst"
- case OpcodeF32const:
- return "F32const"
- case OpcodeF64const:
- return "F64const"
- case OpcodeVconst:
- return "Vconst"
- case OpcodeShuffle:
- return "Shuffle"
- case OpcodeSelect:
- return "Select"
- case OpcodeVanyTrue:
- return "VanyTrue"
- case OpcodeVallTrue:
- return "VallTrue"
- case OpcodeVhighBits:
- return "VhighBits"
- case OpcodeIcmp:
- return "Icmp"
- case OpcodeIcmpImm:
- return "IcmpImm"
- case OpcodeVIcmp:
- return "VIcmp"
- case OpcodeIadd:
- return "Iadd"
- case OpcodeIsub:
- return "Isub"
- case OpcodeImul:
- return "Imul"
- case OpcodeUdiv:
- return "Udiv"
- case OpcodeSdiv:
- return "Sdiv"
- case OpcodeUrem:
- return "Urem"
- case OpcodeSrem:
- return "Srem"
- case OpcodeBand:
- return "Band"
- case OpcodeBor:
- return "Bor"
- case OpcodeBxor:
- return "Bxor"
- case OpcodeBnot:
- return "Bnot"
- case OpcodeRotl:
- return "Rotl"
- case OpcodeRotr:
- return "Rotr"
- case OpcodeIshl:
- return "Ishl"
- case OpcodeUshr:
- return "Ushr"
- case OpcodeSshr:
- return "Sshr"
- case OpcodeClz:
- return "Clz"
- case OpcodeCtz:
- return "Ctz"
- case OpcodePopcnt:
- return "Popcnt"
- case OpcodeFcmp:
- return "Fcmp"
- case OpcodeFadd:
- return "Fadd"
- case OpcodeFsub:
- return "Fsub"
- case OpcodeFmul:
- return "Fmul"
- case OpcodeFdiv:
- return "Fdiv"
- case OpcodeSqmulRoundSat:
- return "SqmulRoundSat"
- case OpcodeSqrt:
- return "Sqrt"
- case OpcodeFneg:
- return "Fneg"
- case OpcodeFabs:
- return "Fabs"
- case OpcodeFcopysign:
- return "Fcopysign"
- case OpcodeFmin:
- return "Fmin"
- case OpcodeFmax:
- return "Fmax"
- case OpcodeCeil:
- return "Ceil"
- case OpcodeFloor:
- return "Floor"
- case OpcodeTrunc:
- return "Trunc"
- case OpcodeNearest:
- return "Nearest"
- case OpcodeBitcast:
- return "Bitcast"
- case OpcodeIreduce:
- return "Ireduce"
- case OpcodeSnarrow:
- return "Snarrow"
- case OpcodeUnarrow:
- return "Unarrow"
- case OpcodeSwidenLow:
- return "SwidenLow"
- case OpcodeSwidenHigh:
- return "SwidenHigh"
- case OpcodeUwidenLow:
- return "UwidenLow"
- case OpcodeUwidenHigh:
- return "UwidenHigh"
- case OpcodeExtIaddPairwise:
- return "IaddPairwise"
- case OpcodeWideningPairwiseDotProductS:
- return "WideningPairwiseDotProductS"
- case OpcodeUExtend:
- return "UExtend"
- case OpcodeSExtend:
- return "SExtend"
- case OpcodeFpromote:
- return "Fpromote"
- case OpcodeFdemote:
- return "Fdemote"
- case OpcodeFvdemote:
- return "Fvdemote"
- case OpcodeFcvtToUint:
- return "FcvtToUint"
- case OpcodeFcvtToSint:
- return "FcvtToSint"
- case OpcodeFcvtToUintSat:
- return "FcvtToUintSat"
- case OpcodeFcvtToSintSat:
- return "FcvtToSintSat"
- case OpcodeFcvtFromUint:
- return "FcvtFromUint"
- case OpcodeFcvtFromSint:
- return "FcvtFromSint"
- case OpcodeAtomicRmw:
- return "AtomicRmw"
- case OpcodeAtomicCas:
- return "AtomicCas"
- case OpcodeAtomicLoad:
- return "AtomicLoad"
- case OpcodeAtomicStore:
- return "AtomicStore"
- case OpcodeFence:
- return "Fence"
- case OpcodeVbor:
- return "Vbor"
- case OpcodeVbxor:
- return "Vbxor"
- case OpcodeVband:
- return "Vband"
- case OpcodeVbandnot:
- return "Vbandnot"
- case OpcodeVbnot:
- return "Vbnot"
- case OpcodeVbitselect:
- return "Vbitselect"
- case OpcodeVIadd:
- return "VIadd"
- case OpcodeVSaddSat:
- return "VSaddSat"
- case OpcodeVUaddSat:
- return "VUaddSat"
- case OpcodeVSsubSat:
- return "VSsubSat"
- case OpcodeVUsubSat:
- return "VUsubSat"
- case OpcodeVAvgRound:
- return "OpcodeVAvgRound"
- case OpcodeVIsub:
- return "VIsub"
- case OpcodeVImin:
- return "VImin"
- case OpcodeVUmin:
- return "VUmin"
- case OpcodeVImax:
- return "VImax"
- case OpcodeVUmax:
- return "VUmax"
- case OpcodeVImul:
- return "VImul"
- case OpcodeVIabs:
- return "VIabs"
- case OpcodeVIneg:
- return "VIneg"
- case OpcodeVIpopcnt:
- return "VIpopcnt"
- case OpcodeVIshl:
- return "VIshl"
- case OpcodeVUshr:
- return "VUshr"
- case OpcodeVSshr:
- return "VSshr"
- case OpcodeVFabs:
- return "VFabs"
- case OpcodeVFmax:
- return "VFmax"
- case OpcodeVFmin:
- return "VFmin"
- case OpcodeVFneg:
- return "VFneg"
- case OpcodeVFadd:
- return "VFadd"
- case OpcodeVFsub:
- return "VFsub"
- case OpcodeVFmul:
- return "VFmul"
- case OpcodeVFdiv:
- return "VFdiv"
- case OpcodeVFcmp:
- return "VFcmp"
- case OpcodeVCeil:
- return "VCeil"
- case OpcodeVFloor:
- return "VFloor"
- case OpcodeVTrunc:
- return "VTrunc"
- case OpcodeVNearest:
- return "VNearest"
- case OpcodeVMaxPseudo:
- return "VMaxPseudo"
- case OpcodeVMinPseudo:
- return "VMinPseudo"
- case OpcodeVSqrt:
- return "VSqrt"
- case OpcodeVFcvtToUintSat:
- return "VFcvtToUintSat"
- case OpcodeVFcvtToSintSat:
- return "VFcvtToSintSat"
- case OpcodeVFcvtFromUint:
- return "VFcvtFromUint"
- case OpcodeVFcvtFromSint:
- return "VFcvtFromSint"
- case OpcodeFvpromoteLow:
- return "FvpromoteLow"
- case OpcodeVZeroExtLoad:
- return "VZeroExtLoad"
- }
- panic(fmt.Sprintf("unknown opcode %d", o))
-}
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
deleted file mode 100644
index b9763791d..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass.go
+++ /dev/null
@@ -1,393 +0,0 @@
-package ssa
-
-import (
- "fmt"
-
- "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
-)
-
-// RunPasses implements Builder.RunPasses.
-//
-// The order here matters; some pass depends on the previous ones.
-//
-// Note that passes suffixed with "Opt" are the optimization passes, meaning that they edit the instructions and blocks
-// while the other passes are not, like passEstimateBranchProbabilities does not edit them, but only calculates the additional information.
-func (b *builder) RunPasses() {
- b.runPreBlockLayoutPasses()
- b.runBlockLayoutPass()
- b.runPostBlockLayoutPasses()
- b.runFinalizingPasses()
-}
-
-func (b *builder) runPreBlockLayoutPasses() {
- passSortSuccessors(b)
- passDeadBlockEliminationOpt(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.
- // WebAssembly program shouldn't result in irreducible CFG, but we should handle it properly in just in case.
- // See FixIrreducible pass in LLVM: https://llvm.org/doxygen/FixIrreducible_8cpp_source.html
-
- // TODO: implement more optimization passes like:
- // block coalescing.
- // Copy-propagation.
- // Constant folding.
- // Common subexpression elimination.
- // Arithmetic simplifications.
- // and more!
-
- // passDeadCodeEliminationOpt could be more accurate if we do this after other optimizations.
- passDeadCodeEliminationOpt(b)
- b.donePreBlockLayoutPasses = true
-}
-
-func (b *builder) runBlockLayoutPass() {
- if !b.donePreBlockLayoutPasses {
- panic("runBlockLayoutPass must be called after all pre passes are done")
- }
- passLayoutBlocks(b)
- b.doneBlockLayout = true
-}
-
-// runPostBlockLayoutPasses runs the post block layout passes. After this point, CFG is somewhat stable,
-// but still can be modified before finalizing passes. At this point, critical edges are split by passLayoutBlocks.
-func (b *builder) runPostBlockLayoutPasses() {
- if !b.doneBlockLayout {
- panic("runPostBlockLayoutPasses must be called after block layout pass is done")
- }
- // TODO: Do more. e.g. tail duplication, loop unrolling, etc.
-
- b.donePostBlockLayoutPasses = true
-}
-
-// runFinalizingPasses runs the finalizing passes. After this point, CFG should not be modified.
-func (b *builder) runFinalizingPasses() {
- if !b.donePostBlockLayoutPasses {
- panic("runFinalizingPasses must be called after post block layout passes are done")
- }
- // Critical edges are split, so we fix the loop nesting forest.
- passBuildLoopNestingForest(b)
- passBuildDominatorTree(b)
- // Now that we know the final placement of the blocks, we can explicitly mark the fallthrough jumps.
- b.markFallthroughJumps()
-}
-
-// passDeadBlockEliminationOpt searches the unreachable blocks, and sets the basicBlock.invalid flag true if so.
-func passDeadBlockEliminationOpt(b *builder) {
- entryBlk := b.entryBlk()
- 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]
- reachableBlk.visited = 1
-
- if !reachableBlk.sealed && !reachableBlk.ReturnBlock() {
- panic(fmt.Sprintf("%s is not sealed", reachableBlk))
- }
-
- if wazevoapi.SSAValidationEnabled {
- reachableBlk.validate(b)
- }
-
- for _, succ := range reachableBlk.success {
- if succ.visited == 1 {
- continue
- }
- b.blkStack = append(b.blkStack, succ)
- }
- }
-
- for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() {
- 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) {
- 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
- // that removing many PHIs results in the reduction of the total instructions, not because of this indefinite iteration is
- // 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.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() {
- params := blk.params.View()
- paramNum := len(params)
-
- for paramIndex := 0; paramIndex < paramNum; paramIndex++ {
- phiValue := params[paramIndex]
- redundant := true
-
- nonSelfReferencingValue := ValueInvalid
- for predIndex := range blk.preds {
- br := blk.preds[predIndex].branch
- // Resolve the alias in the arguments so that we could use the previous iteration's result.
- b.resolveArgumentAlias(br)
- pred := br.vs.View()[paramIndex]
- if pred == phiValue {
- // This is self-referencing: PHI from the same PHI.
- continue
- }
-
- if !nonSelfReferencingValue.Valid() {
- nonSelfReferencingValue = pred
- continue
- }
-
- if nonSelfReferencingValue != pred {
- redundant = false
- break
- }
- }
-
- if !nonSelfReferencingValue.Valid() {
- // This shouldn't happen, and must be a bug in builder.go.
- panic("BUG: params added but only self-referencing")
- }
-
- if redundant {
- redundantParams = append(redundantParams, redundantParam{
- index: paramIndex, uniqueValue: nonSelfReferencingValue,
- })
- }
- }
-
- if len(redundantParams) == 0 {
- continue
- }
- changed = true
-
- // Remove the redundant PHIs from the argument list of branching instructions.
- for predIndex := range blk.preds {
- redundantParamsCur, predParamCur := 0, 0
- predBlk := blk.preds[predIndex]
- branchInst := predBlk.branch
- view := branchInst.vs.View()
- for argIndex, value := range view {
- if len(redundantParams) == redundantParamsCur ||
- redundantParams[redundantParamsCur].index != argIndex {
- view[predParamCur] = value
- predParamCur++
- } else {
- redundantParamsCur++
- }
- }
- branchInst.vs.Cut(predParamCur)
- }
-
- // Still need to have the definition of the value of the PHI (previously as the parameter).
- 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, redundantValue.uniqueValue)
- }
-
- // Finally, Remove the param from the blk.
- paramsCur, redundantParamsCur := 0, 0
- for paramIndex := 0; paramIndex < paramNum; paramIndex++ {
- param := params[paramIndex]
- if len(redundantParams) == redundantParamsCur || redundantParams[redundantParamsCur].index != paramIndex {
- params[paramsCur] = param
- paramsCur++
- } else {
- redundantParamsCur++
- }
- }
- blk.params.Cut(paramsCur)
-
- // Clears the map for the next iteration.
- redundantParams = redundantParams[:0]
- }
-
- if !changed {
- break
- }
- }
-
- // Reuse the slice for the future passes.
- b.redundantParams = redundantParams
-}
-
-// passDeadCodeEliminationOpt traverses all the instructions, and calculates the reference count of each Value, and
-// eliminates all the unnecessary instructions whose ref count is zero.
-// The results are stored at builder.valueRefCounts. This also assigns a InstructionGroupID to each Instruction
-// during the process. This is the last SSA-level optimization pass and after this,
-// the SSA function is ready to be used by backends.
-//
-// 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.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.
- liveInstructions := b.instStack[:0]
- // During the process, we will assign InstructionGroupID to each instruction, which is not
- // relevant to dead code elimination, but we need in the backend.
- var gid InstructionGroupID
- for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() {
- for cur := blk.rootInstr; cur != nil; cur = cur.next {
- cur.gid = gid
- switch cur.sideEffect() {
- case sideEffectTraps:
- // The trappable should always be alive.
- liveInstructions = append(liveInstructions, cur)
- case sideEffectStrict:
- liveInstructions = append(liveInstructions, cur)
- // The strict side effect should create different instruction groups.
- gid++
- }
- }
- }
-
- // Find all the instructions referenced by live instructions transitively.
- for len(liveInstructions) > 0 {
- tail := len(liveInstructions) - 1
- live := liveInstructions[tail]
- liveInstructions = liveInstructions[:tail]
- if live.live {
- // If it's already marked alive, this is referenced multiple times,
- // so we can skip it.
- continue
- }
- live.live = true
-
- // Before we walk, we need to resolve the alias first.
- b.resolveArgumentAlias(live)
-
- v1, v2, v3, vs := live.Args()
- if v1.Valid() {
- producingInst := b.InstructionOfValue(v1)
- if producingInst != nil {
- liveInstructions = append(liveInstructions, producingInst)
- }
- }
-
- if v2.Valid() {
- producingInst := b.InstructionOfValue(v2)
- if producingInst != nil {
- liveInstructions = append(liveInstructions, producingInst)
- }
- }
-
- if v3.Valid() {
- producingInst := b.InstructionOfValue(v3)
- if producingInst != nil {
- liveInstructions = append(liveInstructions, producingInst)
- }
- }
-
- for _, v := range vs {
- producingInst := b.InstructionOfValue(v)
- if producingInst != nil {
- liveInstructions = append(liveInstructions, producingInst)
- }
- }
- }
-
- // Now that all the live instructions are flagged as live=true, we eliminate all dead instructions.
- for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() {
- for cur := blk.rootInstr; cur != nil; cur = cur.next {
- if !cur.live {
- // Remove the instruction from the list.
- if prev := cur.prev; prev != nil {
- prev.next = cur.next
- } else {
- blk.rootInstr = cur.next
- }
- if next := cur.next; next != nil {
- next.prev = cur.prev
- }
- continue
- }
-
- // If the value alive, we can be sure that arguments are used definitely.
- // Hence, we can increment the value reference counts.
- v1, v2, v3, vs := cur.Args()
- if v1.Valid() {
- b.incRefCount(v1.ID(), cur)
- }
- if v2.Valid() {
- b.incRefCount(v2.ID(), cur)
- }
- if v3.Valid() {
- b.incRefCount(v3.ID(), cur)
- }
- for _, v := range vs {
- b.incRefCount(v.ID(), cur)
- }
- }
- }
-
- b.instStack = liveInstructions // we reuse the stack for the next iteration.
-}
-
-func (b *builder) incRefCount(id ValueID, from *Instruction) {
- if wazevoapi.SSALoggingEnabled {
- fmt.Printf("v%d referenced from %v\n", id, from.Format(b))
- }
- info := &b.valuesInfo[id]
- info.RefCount++
-}
-
-// passNopInstElimination eliminates the instructions which is essentially a no-op.
-func passNopInstElimination(b *builder) {
- 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.InstructionOfValue(amount)
- if definingInst == nil {
- // If there's no defining instruction, that means the amount is coming from the parameter.
- continue
- }
- if definingInst.Constant() {
- v := definingInst.ConstantVal()
-
- if x.Type().Bits() == 64 {
- v = v % 64
- } else {
- v = v % 32
- }
- if v == 0 {
- b.alias(cur.Return(), x)
- }
- }
- }
- }
- }
-}
-
-// passSortSuccessors sorts the successors of each block in the natural program order.
-func passSortSuccessors(b *builder) {
- for i := 0; i < b.basicBlocksPool.Allocated(); i++ {
- blk := b.basicBlocksPool.View(i)
- sortBlocks(blk.success)
- }
-}
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
deleted file mode 100644
index 0118e8b2e..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_blk_layouts.go
+++ /dev/null
@@ -1,334 +0,0 @@
-package ssa
-
-import (
- "fmt"
- "strings"
-
- "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
-)
-
-// passLayoutBlocks implements Builder.LayoutBlocks. This re-organizes builder.reversePostOrderedBasicBlocks.
-//
-// TODO: there are tons of room for improvement here. e.g. LLVM has BlockPlacementPass using BlockFrequencyInfo,
-// BranchProbabilityInfo, and LoopInfo to do a much better job. Also, if we have the profiling instrumentation
-// like ball-larus algorithm, then we could do profile-guided optimization. Basically all of them are trying
-// to maximize the fall-through opportunities which is most efficient.
-//
-// Here, fallthrough happens when a block ends with jump instruction whose target is the right next block in the
-// builder.reversePostOrderedBasicBlocks.
-//
-// Currently, we just place blocks using the DFS reverse post-order of the dominator tree with the heuristics:
-// 1. a split edge trampoline towards a loop header will be placed as a fallthrough.
-// 2. we invert the brz and brnz if it makes the fallthrough more likely.
-//
-// This heuristic is done in maybeInvertBranches function.
-func passLayoutBlocks(b *builder) {
- // 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.
- nonSplitBlocks := b.blkStack[:0]
- for i, blk := range b.reversePostOrderedBasicBlocks {
- if !blk.Valid() {
- continue
- }
- nonSplitBlocks = append(nonSplitBlocks, blk)
- if i != len(b.reversePostOrderedBasicBlocks)-1 {
- _ = maybeInvertBranches(b, blk, b.reversePostOrderedBasicBlocks[i+1])
- }
- }
-
- var trampolines []*basicBlock
-
- // Reset the order slice since we update on the fly by splitting critical edges.
- b.reversePostOrderedBasicBlocks = b.reversePostOrderedBasicBlocks[:0]
- uninsertedTrampolines := b.blkStack2[:0]
- for _, blk := range nonSplitBlocks {
- for i := range blk.preds {
- pred := blk.preds[i].blk
- 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)
- 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)
- blk.visited = 1 // mark as inserted.
-
- if len(blk.success) < 2 {
- // There won't be critical edge originating from this block.
- continue
- } else if blk.currentInstr.opcode == OpcodeBrTable {
- // We don't split critical edges here, because at the construction site of BrTable, we already split the edges.
- continue
- }
-
- for sidx, succ := range blk.success {
- if !succ.ReturnBlock() && // If the successor is a return block, we need to split the edge any way because we need "epilogue" to be inserted.
- // Plus if there's no multiple incoming edges to this successor, (pred, succ) is not critical.
- len(succ.preds) < 2 {
- continue
- }
-
- // Otherwise, we are sure this is a critical edge. To modify the CFG, we need to find the predecessor info
- // from the successor.
- var predInfo *basicBlockPredecessorInfo
- for i := range succ.preds { // This linear search should not be a problem since the number of predecessors should almost always small.
- pred := &succ.preds[i]
- if pred.blk == blk {
- predInfo = pred
- break
- }
- }
-
- if predInfo == nil {
- // This must be a bug in somewhere around branch manipulation.
- panic("BUG: predecessor info not found while the successor exists in successors list")
- }
-
- if wazevoapi.SSALoggingEnabled {
- fmt.Printf("trying to split edge from %d->%d at %s\n",
- blk.ID(), succ.ID(), predInfo.branch.Format(b))
- }
-
- trampoline := b.splitCriticalEdge(blk, succ, predInfo)
- // Update the successors slice because the target is no longer the original `succ`.
- blk.success[sidx] = trampoline
-
- if wazevoapi.SSAValidationEnabled {
- trampolines = append(trampolines, trampoline)
- }
-
- if wazevoapi.SSALoggingEnabled {
- fmt.Printf("edge split from %d->%d at %s as %d->%d->%d \n",
- blk.ID(), succ.ID(), predInfo.branch.Format(b),
- blk.ID(), trampoline.ID(), succ.ID())
- }
-
- fallthroughBranch := blk.currentInstr
- 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.
- } else {
- uninsertedTrampolines = append(uninsertedTrampolines, trampoline)
- }
- }
-
- for _, trampoline := range uninsertedTrampolines {
- 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)
- 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.
- }
-
- if wazevoapi.SSALoggingEnabled {
- var bs []string
- for _, blk := range b.reversePostOrderedBasicBlocks {
- bs = append(bs, blk.Name())
- }
- fmt.Println("ordered blocks: ", strings.Join(bs, ", "))
- }
-
- if wazevoapi.SSAValidationEnabled {
- for _, trampoline := range trampolines {
- if trampoline.visited != 1 {
- panic("BUG: trampoline block not inserted: " + trampoline.formatHeader(b))
- }
- trampoline.validate(b)
- }
- }
-
- // Reuse the stack for the next iteration.
- b.blkStack2 = uninsertedTrampolines[:0]
-}
-
-// markFallthroughJumps finds the fallthrough jumps and marks them as such.
-func (b *builder) markFallthroughJumps() {
- l := len(b.reversePostOrderedBasicBlocks) - 1
- for i, blk := range b.reversePostOrderedBasicBlocks {
- if i < l {
- cur := blk.currentInstr
- if cur.opcode == OpcodeJump && BasicBlockID(cur.rValue) == b.reversePostOrderedBasicBlocks[i+1].id {
- cur.AsFallthroughJump()
- }
- }
- }
-}
-
-// maybeInvertBranches inverts the branch instructions if it is likely possible to the fallthrough more likely with simple heuristics.
-// nextInRPO is the next block in the reverse post-order.
-//
-// Returns true if the branch is inverted for testing purpose.
-func maybeInvertBranches(b *builder, now *basicBlock, nextInRPO *basicBlock) bool {
- fallthroughBranch := now.currentInstr
- if fallthroughBranch.opcode == OpcodeBrTable {
- return false
- }
-
- condBranch := fallthroughBranch.prev
- if condBranch == nil || (condBranch.opcode != OpcodeBrnz && condBranch.opcode != OpcodeBrz) {
- return false
- }
-
- if len(fallthroughBranch.vs.View()) != 0 || len(condBranch.vs.View()) != 0 {
- // If either one of them has arguments, we don't invert the branches.
- return false
- }
-
- // 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 := 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,
- // because the edge is likely to be critical edge for complex loops (e.g. loop with branches inside it).
- // That means, we will split the edge in the end of LayoutBlocks function, and insert the trampoline block
- // right after this block, which will be fallthrough in any way.
- return false
- } else if condTarget.loopHeader {
- // On the other hand, if the condBranch's target is loopHeader, we invert the condition of the branch
- // so that we could get the fallthrough to the trampoline block.
- goto invert
- }
-
- if fallthroughTarget == nextInRPO {
- // Also, if the tail's target is the next block in the reverse post-order, we don't need to do anything here,
- // because if this is not critical edge, we would end up placing these two blocks adjacent to each other.
- // Even if it is the critical edge, we place the trampoline block right after this block, which will be fallthrough in any way.
- return false
- } else if condTarget == nextInRPO {
- // If the condBranch's target is the next block in the reverse post-order, we invert the condition of the branch
- // so that we could get the fallthrough to the block.
- goto invert
- } else {
- return false
- }
-
-invert:
- for i := range fallthroughTarget.preds {
- pred := &fallthroughTarget.preds[i]
- if pred.branch == fallthroughBranch {
- pred.branch = condBranch
- break
- }
- }
- for i := range condTarget.preds {
- pred := &condTarget.preds[i]
- if pred.branch == condBranch {
- pred.branch = fallthroughBranch
- break
- }
- }
-
- condBranch.InvertBrx()
- 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())
- }
-
- return true
-}
-
-// splitCriticalEdge splits the critical edge between the given predecessor (`pred`) and successor (owning `predInfo`).
-//
-// - `pred` is the source of the critical edge,
-// - `succ` is the destination of the critical edge,
-// - `predInfo` is the predecessor info in the succ.preds slice which represents the critical edge.
-//
-// Why splitting critical edges is important? See following links:
-//
-// - https://en.wikipedia.org/wiki/Control-flow_graph
-// - https://nickdesaulniers.github.io/blog/2023/01/27/critical-edge-splitting/
-//
-// The returned basic block is the trampoline block which is inserted to split the critical edge.
-func (b *builder) splitCriticalEdge(pred, succ *basicBlock, predInfo *basicBlockPredecessorInfo) *basicBlock {
- // In the following, we convert the following CFG:
- //
- // pred --(originalBranch)--> succ
- //
- // to the following CFG:
- //
- // pred --(newBranch)--> trampoline --(originalBranch)-> succ
- //
- // where trampoline is a new basic block which is created to split the critical edge.
-
- trampoline := b.allocateBasicBlock()
- if int(trampoline.id) >= len(b.dominators) {
- b.dominators = append(b.dominators, make([]*basicBlock, trampoline.id+1)...)
- }
- b.dominators[trampoline.id] = pred
-
- originalBranch := predInfo.branch
-
- // Replace originalBranch with the newBranch.
- newBranch := b.AllocateInstruction()
- newBranch.opcode = originalBranch.opcode
- newBranch.rValue = Value(trampoline.ID())
- switch originalBranch.opcode {
- case OpcodeJump:
- case OpcodeBrz, OpcodeBrnz:
- originalBranch.opcode = OpcodeJump // Trampoline consists of one unconditional branch.
- newBranch.v = originalBranch.v
- originalBranch.v = ValueInvalid
- default:
- panic("BUG: critical edge shouldn't be originated from br_table")
- }
- swapInstruction(pred, originalBranch, newBranch)
-
- // Replace the original branch with the new branch.
- trampoline.rootInstr = originalBranch
- trampoline.currentInstr = originalBranch
- trampoline.success = append(trampoline.success, succ) // Do not use []*basicBlock{pred} because we might have already allocated the slice.
- trampoline.preds = append(trampoline.preds, // same as ^.
- basicBlockPredecessorInfo{blk: pred, branch: newBranch})
- b.Seal(trampoline)
-
- // Update the original branch to point to the trampoline.
- predInfo.blk = trampoline
- predInfo.branch = originalBranch
-
- if wazevoapi.SSAValidationEnabled {
- trampoline.validate(b)
- }
-
- if len(trampoline.params.View()) > 0 {
- panic("trampoline should not have params")
- }
-
- // Assign the same order as the original block so that this will be placed before the actual destination.
- trampoline.reversePostOrder = pred.reversePostOrder
- return trampoline
-}
-
-// swapInstruction replaces `old` in the block `blk` with `New`.
-func swapInstruction(blk *basicBlock, old, New *Instruction) {
- if blk.rootInstr == old {
- blk.rootInstr = New
- next := old.next
- New.next = next
- next.prev = New
- } else {
- if blk.currentInstr == old {
- blk.currentInstr = New
- }
- prev := old.prev
- prev.next, New.prev = New, prev
- if next := old.next; next != nil {
- New.next, next.prev = next, New
- }
- }
- old.prev, old.next = nil, nil
-}
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
deleted file mode 100644
index e8288c4bd..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/pass_cfg.go
+++ /dev/null
@@ -1,313 +0,0 @@
-package ssa
-
-import (
- "fmt"
- "math"
- "strings"
-
- "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
-)
-
-// passCalculateImmediateDominators calculates immediate dominators for each basic block.
-// The result is stored in b.dominators. This make it possible for the following passes to
-// use builder.isDominatedBy to check if a block is dominated by another block.
-//
-// 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]
-
- // Store the reverse postorder from the entrypoint into reversePostOrder slice.
- // This calculation of reverse postorder is not described in the paper,
- // so we use heuristic to calculate it so that we could potentially handle arbitrary
- // complex CFGs under the assumption that success is sorted in program's natural order.
- // That means blk.success[i] always appears before blk.success[i+1] in the source program,
- // 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.
- 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
- entryBlk.visited = visitStateSeen
- for len(exploreStack) > 0 {
- tail := len(exploreStack) - 1
- blk := exploreStack[tail]
- exploreStack = exploreStack[:tail]
- switch blk.visited {
- case visitStateUnseen:
- // This is likely a bug in the frontend.
- panic("BUG: unsupported CFG")
- case visitStateSeen:
- // This is the first time to pop this block, and we have to see the successors first.
- // So push this block again to the stack.
- exploreStack = append(exploreStack, blk)
- // And push the successors to the stack if necessary.
- for _, succ := range blk.success {
- if succ.ReturnBlock() || succ.invalid {
- continue
- }
- if succ.visited == visitStateUnseen {
- succ.visited = visitStateSeen
- exploreStack = append(exploreStack, succ)
- }
- }
- // Finally, we could pop this block once we pop all of its successors.
- 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.
- for i := len(reversePostOrder)/2 - 1; i >= 0; i-- {
- j := len(reversePostOrder) - 1 - i
- reversePostOrder[i], reversePostOrder[j] = reversePostOrder[j], reversePostOrder[i]
- }
-
- for i, blk := range reversePostOrder {
- blk.reversePostOrder = int32(i)
- }
-
- // Reuse the dominators slice if possible from the previous computation of function.
- b.dominators = b.dominators[:cap(b.dominators)]
- if len(b.dominators) < b.basicBlocksPool.Allocated() {
- // Generously reserve space in the slice because the slice will be reused future allocation.
- b.dominators = append(b.dominators, make([]*basicBlock, b.basicBlocksPool.Allocated())...)
- }
- calculateDominators(reversePostOrder, b.dominators)
-
- // Reuse the slices for the future use.
- b.blkStack = exploreStack
-
- // For the following passes.
- b.reversePostOrderedBasicBlocks = reversePostOrder
-
- // Ready to detect loops!
- subPassLoopDetection(b)
-}
-
-// calculateDominators calculates the immediate dominator of each node in the CFG, and store the result in `doms`.
-// The algorithm is based on the one described in the paper "A Simple, Fast Dominance Algorithm"
-// https://www.cs.rice.edu/~keith/EMBED/dom.pdf which is a faster/simple alternative to the well known Lengauer-Tarjan algorithm.
-//
-// The following code almost matches the pseudocode in the paper with one exception (see the code comment below).
-//
-// The result slice `doms` must be pre-allocated with the size larger than the size of dfsBlocks.
-func calculateDominators(reversePostOrderedBlks []*basicBlock, doms []*basicBlock) {
- entry, reversePostOrderedBlks := reversePostOrderedBlks[0], reversePostOrderedBlks[1: /* skips entry point */]
- for _, blk := range reversePostOrderedBlks {
- doms[blk.id] = nil
- }
- doms[entry.id] = entry
-
- changed := true
- for changed {
- changed = false
- for _, blk := range reversePostOrderedBlks {
- var u *basicBlock
- for i := range blk.preds {
- pred := blk.preds[i].blk
- // Skip if this pred is not reachable yet. Note that this is not described in the paper,
- // but it is necessary to handle nested loops etc.
- if doms[pred.id] == nil {
- continue
- }
-
- if u == nil {
- u = pred
- continue
- } else {
- u = intersect(doms, u, pred)
- }
- }
- if doms[blk.id] != u {
- doms[blk.id] = u
- changed = true
- }
- }
- }
-}
-
-// intersect returns the common dominator of blk1 and blk2.
-//
-// This is the `intersect` function in the paper.
-func intersect(doms []*basicBlock, blk1 *basicBlock, blk2 *basicBlock) *basicBlock {
- finger1, finger2 := blk1, blk2
- for finger1 != finger2 {
- // Move the 'finger1' upwards to its immediate dominator.
- for finger1.reversePostOrder > finger2.reversePostOrder {
- finger1 = doms[finger1.id]
- }
- // Move the 'finger2' upwards to its immediate dominator.
- for finger2.reversePostOrder > finger1.reversePostOrder {
- finger2 = doms[finger2.id]
- }
- }
- return finger1
-}
-
-// subPassLoopDetection detects loops in the function using the immediate dominators.
-//
-// This is run at the last of passCalculateImmediateDominators.
-func subPassLoopDetection(b *builder) {
- for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() {
- for i := range blk.preds {
- pred := blk.preds[i].blk
- if pred.invalid {
- continue
- }
- if b.isDominatedBy(pred, blk) {
- blk.loopHeader = true
- }
- }
- }
-}
-
-// buildLoopNestingForest builds the loop nesting forest for the function.
-// This must be called after branch splitting since it relies on the CFG.
-func passBuildLoopNestingForest(b *builder) {
- ent := b.entryBlk()
- doms := b.dominators
- for _, blk := range b.reversePostOrderedBasicBlocks {
- n := doms[blk.id]
- for !n.loopHeader && n != ent {
- n = doms[n.id]
- }
-
- if n == ent && blk.loopHeader {
- b.loopNestingForestRoots = append(b.loopNestingForestRoots, blk)
- } else if n == ent {
- } else if n.loopHeader {
- n.loopNestingForestChildren = n.loopNestingForestChildren.Append(&b.varLengthBasicBlockPool, blk)
- }
- }
-
- if wazevoapi.SSALoggingEnabled {
- for _, root := range b.loopNestingForestRoots {
- printLoopNestingForest(root.(*basicBlock), 0)
- }
- }
-}
-
-func printLoopNestingForest(root *basicBlock, depth int) {
- fmt.Println(strings.Repeat("\t", depth), "loop nesting forest root:", root.ID())
- for _, child := range root.loopNestingForestChildren.View() {
- fmt.Println(strings.Repeat("\t", depth+1), "child:", child.ID())
- if child.LoopHeader() {
- printLoopNestingForest(child.(*basicBlock), depth+2)
- }
- }
-}
-
-type dominatorSparseTree struct {
- time int32
- euler []*basicBlock
- first, depth []int32
- table [][]int32
-}
-
-// passBuildDominatorTree builds the dominator tree for the function, and constructs builder.sparseTree.
-func passBuildDominatorTree(b *builder) {
- // First we materialize the children of each node in the dominator tree.
- idoms := b.dominators
- for _, blk := range b.reversePostOrderedBasicBlocks {
- parent := idoms[blk.id]
- if parent == nil {
- panic("BUG")
- } else if parent == blk {
- // This is the entry block.
- continue
- }
- if prev := parent.child; prev == nil {
- parent.child = blk
- } else {
- parent.child = blk
- blk.sibling = prev
- }
- }
-
- // Reset the state from the previous computation.
- 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([]int32, n)...)
- for i := range st.first {
- st.first[i] = -1
- }
- st.depth = append(st.depth[:0], make([]int32, 2*n-1)...)
- st.time = 0
-
- // Start building the sparse tree.
- st.eulerTour(b.entryBlk(), 0)
- st.buildSparseTable()
-}
-
-func (dt *dominatorSparseTree) eulerTour(node *basicBlock, height int32) {
- if wazevoapi.SSALoggingEnabled {
- fmt.Println(strings.Repeat("\t", int(height)), "euler tour:", node.ID())
- }
- dt.euler[dt.time] = node
- dt.depth[dt.time] = height
- if dt.first[node.id] == -1 {
- dt.first[node.id] = dt.time
- }
- dt.time++
-
- for child := node.child; child != nil; child = child.sibling {
- dt.eulerTour(child, height+1)
- dt.euler[dt.time] = node // add the current node again after visiting a child
- dt.depth[dt.time] = height
- dt.time++
- }
-}
-
-// buildSparseTable builds a sparse table for RMQ queries.
-func (dt *dominatorSparseTree) buildSparseTable() {
- n := len(dt.depth)
- k := int(math.Log2(float64(n))) + 1
- table := dt.table
-
- if n >= len(table) {
- table = append(table, make([][]int32, n-len(table)+1)...)
- }
- for i := range table {
- if len(table[i]) < k {
- table[i] = append(table[i], make([]int32, k-len(table[i]))...)
- }
- table[i][0] = int32(i)
- }
-
- for j := 1; 1<<j <= n; j++ {
- for i := 0; i+(1<<j)-1 < n; i++ {
- if dt.depth[table[i][j-1]] < dt.depth[table[i+(1<<(j-1))][j-1]] {
- table[i][j] = table[i][j-1]
- } else {
- table[i][j] = table[i+(1<<(j-1))][j-1]
- }
- }
- }
- dt.table = table
-}
-
-// rmq performs a range minimum query on the sparse table.
-func (dt *dominatorSparseTree) rmq(l, r int32) int32 {
- table := dt.table
- depth := dt.depth
- j := int(math.Log2(float64(r - l + 1)))
- if depth[table[l][j]] <= depth[table[r-(1<<j)+1][j]] {
- return table[l][j]
- }
- return table[r-(1<<j)+1][j]
-}
-
-// findLCA finds the LCA using the Euler tour and RMQ.
-func (dt *dominatorSparseTree) findLCA(u, v BasicBlockID) *basicBlock {
- first := dt.first
- if first[u] > first[v] {
- u, v = v, u
- }
- return dt.euler[dt.rmq(first[u], first[v])]
-}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/signature.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/signature.go
deleted file mode 100644
index 43483395a..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/signature.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package ssa
-
-import (
- "fmt"
- "strings"
-)
-
-// Signature is a function prototype.
-type Signature struct {
- // ID is a unique identifier for this signature used to lookup.
- ID SignatureID
- // Params and Results are the types of the parameters and results of the function.
- Params, Results []Type
-
- // used is true if this is used by the currently-compiled function.
- // Debugging only.
- used bool
-}
-
-// String implements fmt.Stringer.
-func (s *Signature) String() string {
- str := strings.Builder{}
- str.WriteString(s.ID.String())
- str.WriteString(": ")
- if len(s.Params) > 0 {
- for _, typ := range s.Params {
- str.WriteString(typ.String())
- }
- } else {
- str.WriteByte('v')
- }
- str.WriteByte('_')
- if len(s.Results) > 0 {
- for _, typ := range s.Results {
- str.WriteString(typ.String())
- }
- } else {
- str.WriteByte('v')
- }
- return str.String()
-}
-
-// SignatureID is an unique identifier used to lookup.
-type SignatureID int
-
-// String implements fmt.Stringer.
-func (s SignatureID) String() string {
- return fmt.Sprintf("sig%d", s)
-}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/ssa.go b/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/ssa.go
deleted file mode 100644
index b477e58bd..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/ssa.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// Package ssa is used to construct SSA function. By nature this is free of Wasm specific thing
-// and ISA.
-//
-// We use the "block argument" variant of SSA: https://en.wikipedia.org/wiki/Static_single-assignment_form#Block_arguments
-// which is equivalent to the traditional PHI function based one, but more convenient during optimizations.
-// However, in this package's source code comment, we might use PHI whenever it seems necessary in order to be aligned with
-// existing literatures, e.g. SSA level optimization algorithms are often described using PHI nodes.
-//
-// The rationale doc for the choice of "block argument" by MLIR of LLVM is worth a read:
-// https://mlir.llvm.org/docs/Rationale/Rationale/#block-arguments-vs-phi-nodes
-//
-// The algorithm to resolve variable definitions used here is based on the paper
-// "Simple and Efficient Construction of Static Single Assignment Form": https://link.springer.com/content/pdf/10.1007/978-3-642-37051-9_6.pdf.
-package ssa
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
deleted file mode 100644
index 73daf4269..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/type.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package ssa
-
-type Type byte
-
-const (
- typeInvalid Type = iota
-
- // TODO: add 8, 16 bit types when it's needed for optimizations.
-
- // TypeI32 represents an integer type with 32 bits.
- TypeI32
-
- // TypeI64 represents an integer type with 64 bits.
- TypeI64
-
- // TypeF32 represents 32-bit floats in the IEEE 754.
- TypeF32
-
- // TypeF64 represents 64-bit floats in the IEEE 754.
- TypeF64
-
- // TypeV128 represents 128-bit SIMD vectors.
- TypeV128
-
- // -- Do not add new types after this line. ----
- typeEnd
-)
-
-// String implements fmt.Stringer.
-func (t Type) String() (ret string) {
- switch t {
- case typeInvalid:
- return "invalid"
- case TypeI32:
- return "i32"
- case TypeI64:
- return "i64"
- case TypeF32:
- return "f32"
- case TypeF64:
- return "f64"
- case TypeV128:
- return "v128"
- default:
- panic(int(t))
- }
-}
-
-// IsInt returns true if the type is an integer type.
-func (t Type) IsInt() bool {
- return t == TypeI32 || t == TypeI64
-}
-
-// IsFloat returns true if the type is a floating point type.
-func (t Type) IsFloat() bool {
- return t == TypeF32 || t == TypeF64
-}
-
-// Bits returns the number of bits required to represent the type.
-func (t Type) Bits() byte {
- switch t {
- case TypeI32, TypeF32:
- return 32
- case TypeI64, TypeF64:
- return 64
- case TypeV128:
- return 128
- default:
- panic(int(t))
- }
-}
-
-// Size returns the number of bytes required to represent the type.
-func (t Type) Size() byte {
- return t.Bits() / 8
-}
-
-func (t Type) invalid() bool {
- return t == typeInvalid
-}
-
-// VecLane represents a lane in a SIMD vector.
-type VecLane byte
-
-const (
- VecLaneInvalid VecLane = 1 + iota
- VecLaneI8x16
- VecLaneI16x8
- VecLaneI32x4
- VecLaneI64x2
- VecLaneF32x4
- VecLaneF64x2
-)
-
-// String implements fmt.Stringer.
-func (vl VecLane) String() (ret string) {
- switch vl {
- case VecLaneInvalid:
- return "invalid"
- case VecLaneI8x16:
- return "i8x16"
- case VecLaneI16x8:
- return "i16x8"
- case VecLaneI32x4:
- return "i32x4"
- case VecLaneI64x2:
- return "i64x2"
- case VecLaneF32x4:
- return "f32x4"
- case VecLaneF64x2:
- return "f64x2"
- default:
- panic(int(vl))
- }
-}
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
deleted file mode 100644
index d906e7e35..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/wazevo/ssa/vs.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package ssa
-
-import (
- "fmt"
- "math"
-
- "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
-)
-
-// Variable is a unique identifier for a source program's variable and will correspond to
-// multiple ssa Value(s).
-//
-// For example, `Local 1` is a Variable in WebAssembly, and Value(s) will be created for it
-// whenever it executes `local.set 1`.
-//
-// 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&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.
-//
-// 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.
-type ValueID uint32
-
-const (
- valueIDInvalid ValueID = math.MaxUint32
- ValueInvalid = Value(valueIDInvalid)
-)
-
-// Format creates a debug string for this Value using the data stored in Builder.
-func (v Value) Format(b Builder) string {
- if annotation, ok := b.(*builder).valueAnnotations[v.ID()]; ok {
- return annotation
- }
- return fmt.Sprintf("v%d", v.ID())
-}
-
-func (v Value) formatWithType(b Builder) (ret string) {
- if annotation, ok := b.(*builder).valueAnnotations[v.ID()]; ok {
- ret = annotation + ":" + v.Type().String()
- } else {
- ret = fmt.Sprintf("v%d:%s", v.ID(), v.Type())
- }
-
- 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.valuesInfo[id].RefCount)
- }
- }
- return ret
-}
-
-// Valid returns true if this value is valid.
-func (v Value) Valid() bool {
- return v.ID() != valueIDInvalid
-}
-
-// Type returns the Type of this value.
-func (v Value) Type() Type {
- return Type(v >> 60)
-}
-
-// ID returns the valueID of this value.
-func (v Value) ID() ValueID {
- return ValueID(v)
-}
-
-// setType sets a type to this Value and returns the updated Value.
-func (v Value) setType(typ Type) Value {
- 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.
-type Values = wazevoapi.VarLength[Value]
-
-// ValuesNil is a nil Values.
-var ValuesNil = wazevoapi.NewNilVarLength[Value]()