ssa: removes valueIDToInstruction slice (#2286)
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
@@ -182,11 +182,10 @@ type builder struct {
|
|||||||
loopNestingForestRoots []BasicBlock
|
loopNestingForestRoots []BasicBlock
|
||||||
|
|
||||||
// The followings are used for optimization passes/deterministic compilation.
|
// The followings are used for optimization passes/deterministic compilation.
|
||||||
instStack []*Instruction
|
instStack []*Instruction
|
||||||
valueIDToInstruction []*Instruction
|
blkStack []*basicBlock
|
||||||
blkStack []*basicBlock
|
blkStack2 []*basicBlock
|
||||||
blkStack2 []*basicBlock
|
redundantParams []redundantParam
|
||||||
redundantParams []redundantParam
|
|
||||||
|
|
||||||
// blockIterCur is used to implement blockIteratorBegin and blockIteratorNext.
|
// blockIterCur is used to implement blockIteratorBegin and blockIteratorNext.
|
||||||
blockIterCur int
|
blockIterCur int
|
||||||
@@ -291,7 +290,6 @@ func (b *builder) Init(s *Signature) {
|
|||||||
for v := ValueID(0); v < b.nextValueID; v++ {
|
for v := ValueID(0); v < b.nextValueID; v++ {
|
||||||
delete(b.valueAnnotations, v)
|
delete(b.valueAnnotations, v)
|
||||||
b.valuesInfo[v] = ValueInfo{alias: ValueInvalid}
|
b.valuesInfo[v] = ValueInfo{alias: ValueInvalid}
|
||||||
b.valueIDToInstruction[v] = nil
|
|
||||||
}
|
}
|
||||||
b.nextValueID = 0
|
b.nextValueID = 0
|
||||||
b.reversePostOrderedBasicBlocks = b.reversePostOrderedBasicBlocks[:0]
|
b.reversePostOrderedBasicBlocks = b.reversePostOrderedBasicBlocks[:0]
|
||||||
@@ -397,7 +395,7 @@ func (b *builder) InsertInstruction(instr *Instruction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r1 := b.allocateValue(t1)
|
r1 := b.allocateValue(t1)
|
||||||
instr.rValue = r1
|
instr.rValue = r1.setInstructionID(instr.id)
|
||||||
|
|
||||||
tsl := len(ts)
|
tsl := len(ts)
|
||||||
if tsl == 0 {
|
if tsl == 0 {
|
||||||
@@ -406,7 +404,8 @@ func (b *builder) InsertInstruction(instr *Instruction) {
|
|||||||
|
|
||||||
rValues := b.varLengthPool.Allocate(tsl)
|
rValues := b.varLengthPool.Allocate(tsl)
|
||||||
for i := 0; i < tsl; i++ {
|
for i := 0; i < tsl; i++ {
|
||||||
rValues = rValues.Append(&b.varLengthPool, b.allocateValue(ts[i]))
|
rn := b.allocateValue(ts[i])
|
||||||
|
rValues = rValues.Append(&b.varLengthPool, rn.setInstructionID(instr.id))
|
||||||
}
|
}
|
||||||
instr.rValues = rValues
|
instr.rValues = rValues
|
||||||
}
|
}
|
||||||
@@ -776,3 +775,13 @@ func (b *builder) LoopNestingForestRoots() []BasicBlock {
|
|||||||
func (b *builder) LowestCommonAncestor(blk1, blk2 BasicBlock) BasicBlock {
|
func (b *builder) LowestCommonAncestor(blk1, blk2 BasicBlock) BasicBlock {
|
||||||
return b.sparseTree.findLCA(blk1.ID(), blk2.ID())
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -243,9 +243,6 @@ func passDeadCodeEliminationOpt(b *builder) {
|
|||||||
view[i].alias = ValueInvalid
|
view[i].alias = ValueInvalid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if nvid >= len(b.valueIDToInstruction) {
|
|
||||||
b.valueIDToInstruction = append(b.valueIDToInstruction, make([]*Instruction, nvid-len(b.valueIDToInstruction)+1)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// First, we gather all the instructions with side effects.
|
// First, we gather all the instructions with side effects.
|
||||||
liveInstructions := b.instStack[:0]
|
liveInstructions := b.instStack[:0]
|
||||||
@@ -264,14 +261,6 @@ func passDeadCodeEliminationOpt(b *builder) {
|
|||||||
// The strict side effect should create different instruction groups.
|
// The strict side effect should create different instruction groups.
|
||||||
gid++
|
gid++
|
||||||
}
|
}
|
||||||
|
|
||||||
r1, rs := cur.Returns()
|
|
||||||
if r1.Valid() {
|
|
||||||
b.valueIDToInstruction[r1.ID()] = cur
|
|
||||||
}
|
|
||||||
for _, r := range rs {
|
|
||||||
b.valueIDToInstruction[r.ID()] = cur
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,28 +281,28 @@ func passDeadCodeEliminationOpt(b *builder) {
|
|||||||
|
|
||||||
v1, v2, v3, vs := live.Args()
|
v1, v2, v3, vs := live.Args()
|
||||||
if v1.Valid() {
|
if v1.Valid() {
|
||||||
producingInst := b.valueIDToInstruction[v1.ID()]
|
producingInst := b.instructionOfValue(v1)
|
||||||
if producingInst != nil {
|
if producingInst != nil {
|
||||||
liveInstructions = append(liveInstructions, producingInst)
|
liveInstructions = append(liveInstructions, producingInst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v2.Valid() {
|
if v2.Valid() {
|
||||||
producingInst := b.valueIDToInstruction[v2.ID()]
|
producingInst := b.instructionOfValue(v2)
|
||||||
if producingInst != nil {
|
if producingInst != nil {
|
||||||
liveInstructions = append(liveInstructions, producingInst)
|
liveInstructions = append(liveInstructions, producingInst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v3.Valid() {
|
if v3.Valid() {
|
||||||
producingInst := b.valueIDToInstruction[v3.ID()]
|
producingInst := b.instructionOfValue(v3)
|
||||||
if producingInst != nil {
|
if producingInst != nil {
|
||||||
liveInstructions = append(liveInstructions, producingInst)
|
liveInstructions = append(liveInstructions, producingInst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range vs {
|
for _, v := range vs {
|
||||||
producingInst := b.valueIDToInstruction[v.ID()]
|
producingInst := b.instructionOfValue(v)
|
||||||
if producingInst != nil {
|
if producingInst != nil {
|
||||||
liveInstructions = append(liveInstructions, producingInst)
|
liveInstructions = append(liveInstructions, producingInst)
|
||||||
}
|
}
|
||||||
@@ -367,29 +356,13 @@ func (b *builder) incRefCount(id ValueID, from *Instruction) {
|
|||||||
|
|
||||||
// passNopInstElimination eliminates the instructions which is essentially a no-op.
|
// passNopInstElimination eliminates the instructions which is essentially a no-op.
|
||||||
func passNopInstElimination(b *builder) {
|
func passNopInstElimination(b *builder) {
|
||||||
if int(b.nextValueID) >= len(b.valueIDToInstruction) {
|
|
||||||
b.valueIDToInstruction = append(b.valueIDToInstruction, make([]*Instruction, int(b.nextValueID)-len(b.valueIDToInstruction)+1)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() {
|
|
||||||
for cur := blk.rootInstr; cur != nil; cur = cur.next {
|
|
||||||
r1, rs := cur.Returns()
|
|
||||||
if r1.Valid() {
|
|
||||||
b.valueIDToInstruction[r1.ID()] = cur
|
|
||||||
}
|
|
||||||
for _, r := range rs {
|
|
||||||
b.valueIDToInstruction[r.ID()] = cur
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() {
|
for blk := b.blockIteratorBegin(); blk != nil; blk = b.blockIteratorNext() {
|
||||||
for cur := blk.rootInstr; cur != nil; cur = cur.next {
|
for cur := blk.rootInstr; cur != nil; cur = cur.next {
|
||||||
switch cur.Opcode() {
|
switch cur.Opcode() {
|
||||||
// TODO: add more logics here.
|
// TODO: add more logics here.
|
||||||
case OpcodeIshl, OpcodeSshr, OpcodeUshr:
|
case OpcodeIshl, OpcodeSshr, OpcodeUshr:
|
||||||
x, amount := cur.Arg2()
|
x, amount := cur.Arg2()
|
||||||
definingInst := b.valueIDToInstruction[amount.ID()]
|
definingInst := b.instructionOfValue(amount)
|
||||||
if definingInst == nil {
|
if definingInst == nil {
|
||||||
// If there's no defining instruction, that means the amount is coming from the parameter.
|
// If there's no defining instruction, that means the amount is coming from the parameter.
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ func (v Variable) getType() Type {
|
|||||||
// Value represents an SSA value with a type information. The relationship with Variable is 1: N (including 0),
|
// 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.
|
// that means there might be multiple Variable(s) for a Value.
|
||||||
//
|
//
|
||||||
// Higher 32-bit is used to store Type for this value.
|
// 32 to 59-bit is used to store the unique identifier of the Instruction that generates this value if any.
|
||||||
|
// 60 to 63-bit is used to store Type for this value.
|
||||||
type Value uint64
|
type Value uint64
|
||||||
|
|
||||||
// ValueID is the lower 32bit of Value, which is the pure identifier of Value without type info.
|
// ValueID is the lower 32bit of Value, which is the pure identifier of Value without type info.
|
||||||
@@ -80,7 +81,7 @@ func (v Value) Valid() bool {
|
|||||||
|
|
||||||
// Type returns the Type of this value.
|
// Type returns the Type of this value.
|
||||||
func (v Value) Type() Type {
|
func (v Value) Type() Type {
|
||||||
return Type(v >> 32)
|
return Type(v >> 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID returns the valueID of this value.
|
// ID returns the valueID of this value.
|
||||||
@@ -90,7 +91,20 @@ func (v Value) ID() ValueID {
|
|||||||
|
|
||||||
// setType sets a type to this Value and returns the updated Value.
|
// setType sets a type to this Value and returns the updated Value.
|
||||||
func (v Value) setType(typ Type) Value {
|
func (v Value) setType(typ Type) Value {
|
||||||
return v | Value(typ)<<32
|
return v | Value(typ)<<60
|
||||||
|
}
|
||||||
|
|
||||||
|
// setInstructionID sets an Instruction.id to this Value and returns the updated Value.
|
||||||
|
func (v Value) setInstructionID(id int) Value {
|
||||||
|
if id < 0 || uint(id) >= 1<<28 {
|
||||||
|
panic(fmt.Sprintf("Too large instruction ID: %d", id))
|
||||||
|
}
|
||||||
|
return v | Value(id)<<32
|
||||||
|
}
|
||||||
|
|
||||||
|
// instructionID() returns the Instruction.id of this Value.
|
||||||
|
func (v Value) instructionID() int {
|
||||||
|
return int(v>>32) & 0x0fffffff
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values is a slice of Value. Use this instead of []Value to reuse the underlying memory.
|
// Values is a slice of Value. Use this instead of []Value to reuse the underlying memory.
|
||||||
|
|||||||
14
internal/engine/wazevo/ssa/vs_test.go
Normal file
14
internal/engine/wazevo/ssa/vs_test.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package ssa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValue_InstructionID(t *testing.T) {
|
||||||
|
v := Value(1234).setType(TypeI32).setInstructionID(5678)
|
||||||
|
require.Equal(t, ValueID(1234), v.ID())
|
||||||
|
require.Equal(t, 5678, v.instructionID())
|
||||||
|
require.Equal(t, TypeI32, v.Type())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user