Repository: tetratelabs/wazero
Pull request #2287 (2024-07-10 16:05:45)

backend: removes unnecessary ValueDefinition fields
```
goos: darwin
goarch: arm64
pkg: github.com/tetratelabs/wazero
                      │  old.txt   │             new.txt              │
                      │   sec/op   │   sec/op    vs base              │
Compilation/wazero-10   1.541 ± 0%   1.535 ± 0%  -0.37% (p=0.015 n=6)
Compilation/zig-10      3.422 ± 0%   3.413 ± 0%  -0.27% (p=0.004 n=6)
Compilation/zz-10       14.10 ± 0%   14.08 ± 0%       ~ (p=0.310 n=6)
geomean                 4.205        4.194       -0.25%

                      │   old.txt    │              new.txt               │
                      │     B/op     │     B/op      vs base              │
Compilation/wazero-10   283.0Mi ± 0%   273.4Mi ± 0%  -3.38% (p=0.002 n=6)
Compilation/zig-10      596.7Mi ± 0%   594.7Mi ± 0%  -0.32% (p=0.002 n=6)
Compilation/zz-10       536.5Mi ± 0%   532.4Mi ± 0%  -0.76% (p=0.002 n=6)
geomean                 449.1Mi        442.4Mi       -1.50%

                      │   old.txt   │              new.txt              │
                      │  allocs/op  │  allocs/op   vs base              │
Compilation/wazero-10   485.4k ± 0%   485.2k ± 0%       ~ (p=0.394 n=6)
Compilation/zig-10      275.5k ± 0%   275.5k ± 0%       ~ (p=0.974 n=6)
Compilation/zz-10       627.0k ± 0%   627.1k ± 0%       ~ (p=0.145 n=6)
geomean                 437.7k        437.6k       -0.01%
```

#2182 


Patch:
diff --git a/internal/engine/wazevo/backend/compiler.go b/internal/engine/wazevo/backend/compiler.go
index 0c3d4e58..aea55ee7 100644
--- a/internal/engine/wazevo/backend/compiler.go
+++ b/internal/engine/wazevo/backend/compiler.go
@@ -222,14 +222,13 @@ func (c *compiler) assignVirtualRegisters() {
 			typ := p.Type()
 			vreg := c.AllocateVReg(typ)
 			c.ssaValueToVRegs[pid] = vreg
-			c.ssaValueDefinitions[pid] = SSAValueDefinition{BlockParamValue: p, BlkParamVReg: vreg}
+			c.ssaValueDefinitions[pid] = SSAValueDefinition{V: p}
 			c.ssaTypeOfVRegID[vreg.ID()] = p.Type()
 		}
 
 		// Assigns each value to a virtual register produced by instructions.
 		for cur := blk.Root(); cur != nil; cur = cur.Next() {
 			r, rs := cur.Returns()
-			var N int
 			if r.Valid() {
 				id := r.ID()
 				ssaTyp := r.Type()
@@ -238,11 +237,10 @@ func (c *compiler) assignVirtualRegisters() {
 				c.ssaValueToVRegs[id] = vReg
 				c.ssaValueDefinitions[id] = SSAValueDefinition{
 					Instr:    cur,
-					N:        0,
+					V:        r,
 					RefCount: refCounts[id].RefCount,
 				}
 				c.ssaTypeOfVRegID[vReg.ID()] = ssaTyp
-				N++
 			}
 			for _, r := range rs {
 				id := r.ID()
@@ -251,11 +249,10 @@ func (c *compiler) assignVirtualRegisters() {
 				c.ssaValueToVRegs[id] = vReg
 				c.ssaValueDefinitions[id] = SSAValueDefinition{
 					Instr:    cur,
-					N:        N,
+					V:        r,
 					RefCount: refCounts[id].RefCount,
 				}
 				c.ssaTypeOfVRegID[vReg.ID()] = ssaTyp
-				N++
 			}
 		}
 	}
diff --git a/internal/engine/wazevo/backend/isa/amd64/lower_mem.go b/internal/engine/wazevo/backend/isa/amd64/lower_mem.go
index bee673d2..818f2dbf 100644
--- a/internal/engine/wazevo/backend/isa/amd64/lower_mem.go
+++ b/internal/engine/wazevo/backend/isa/amd64/lower_mem.go
@@ -131,8 +131,8 @@ func (m *machine) lowerAddendsToAmode(x, y addend, offBase uint32) *amode {
 }
 
 func (m *machine) lowerAddend(x *backend.SSAValueDefinition) addend {
-	if x.IsFromBlockParam() {
-		return addend{x.BlkParamVReg, 0, 0}
+	if !x.IsFromInstr() {
+		return addend{m.c.VRegOf(x.V), 0, 0}
 	}
 	// Ensure the addend is not referenced in multiple places; we will discard nested Iadds.
 	op := m.c.MatchInstrOneOf(x, addendsMatchOpcodes[:])
diff --git a/internal/engine/wazevo/backend/isa/amd64/operands.go b/internal/engine/wazevo/backend/isa/amd64/operands.go
index 10b727e7..46fb0f68 100644
--- a/internal/engine/wazevo/backend/isa/amd64/operands.go
+++ b/internal/engine/wazevo/backend/isa/amd64/operands.go
@@ -253,11 +253,11 @@ func (a *amode) String() string {
 }
 
 func (m *machine) getOperand_Mem_Reg(def *backend.SSAValueDefinition) (op operand) {
-	if def.IsFromBlockParam() {
-		return newOperandReg(def.BlkParamVReg)
+	if !def.IsFromInstr() {
+		return newOperandReg(m.c.VRegOf(def.V))
 	}
 
-	if def.SSAValue().Type() == ssa.TypeV128 {
+	if def.V.Type() == ssa.TypeV128 {
 		// SIMD instructions require strict memory alignment, so we don't support the memory operand for V128 at the moment.
 		return m.getOperand_Reg(def)
 	}
@@ -273,8 +273,8 @@ func (m *machine) getOperand_Mem_Reg(def *backend.SSAValueDefinition) (op operan
 }
 
 func (m *machine) getOperand_Mem_Imm32_Reg(def *backend.SSAValueDefinition) (op operand) {
-	if def.IsFromBlockParam() {
-		return newOperandReg(def.BlkParamVReg)
+	if !def.IsFromInstr() {
+		return newOperandReg(m.c.VRegOf(def.V))
 	}
 
 	if m.c.MatchInstr(def, ssa.OpcodeLoad) {
@@ -288,8 +288,8 @@ func (m *machine) getOperand_Mem_Imm32_Reg(def *backend.SSAValueDefinition) (op
 }
 
 func (m *machine) getOperand_Imm32_Reg(def *backend.SSAValueDefinition) (op operand) {
-	if def.IsFromBlockParam() {
-		return newOperandReg(def.BlkParamVReg)
+	if !def.IsFromInstr() {
+		return newOperandReg(m.c.VRegOf(def.V))
 	}
 
 	instr := def.Instr
@@ -325,22 +325,12 @@ func asImm32(val uint64, allowSignExt bool) (uint32, bool) {
 
 func (m *machine) getOperand_Reg(def *backend.SSAValueDefinition) (op operand) {
 	var v regalloc.VReg
-	if def.IsFromBlockParam() {
-		v = def.BlkParamVReg
+	if instr := def.Instr; instr != nil && instr.Constant() {
+		// We inline all the constant instructions so that we could reduce the register usage.
+		v = m.lowerConstant(instr)
+		instr.MarkLowered()
 	} else {
-		instr := def.Instr
-		if instr.Constant() {
-			// We inline all the constant instructions so that we could reduce the register usage.
-			v = m.lowerConstant(instr)
-			instr.MarkLowered()
-		} else {
-			if n := def.N; n == 0 {
-				v = m.c.VRegOf(instr.Return())
-			} else {
-				_, rs := instr.Returns()
-				v = m.c.VRegOf(rs[n-1])
-			}
-		}
+		v = m.c.VRegOf(def.V)
 	}
 	return newOperandReg(v)
 }
diff --git a/internal/engine/wazevo/backend/isa/arm64/lower_instr_operands.go b/internal/engine/wazevo/backend/isa/arm64/lower_instr_operands.go
index d9fbf178..1f564356 100644
--- a/internal/engine/wazevo/backend/isa/arm64/lower_instr_operands.go
+++ b/internal/engine/wazevo/backend/isa/arm64/lower_instr_operands.go
@@ -163,8 +163,8 @@ func (o operand) assignReg(v regalloc.VReg) operand {
 // `mode` is used to extend the operand if the bit length is smaller than mode.bits().
 // If the operand can be expressed as operandKindImm12, `mode` is ignored.
 func (m *machine) getOperand_Imm12_ER_SR_NR(def *backend.SSAValueDefinition, mode extMode) (op operand) {
-	if def.IsFromBlockParam() {
-		return operandNR(def.BlkParamVReg)
+	if !def.IsFromInstr() {
+		return operandNR(m.compiler.VRegOf(def.V))
 	}
 
 	instr := def.Instr
@@ -180,8 +180,8 @@ func (m *machine) getOperand_Imm12_ER_SR_NR(def *backend.SSAValueDefinition, mod
 // getOperand_MaybeNegatedImm12_ER_SR_NR is almost the same as getOperand_Imm12_ER_SR_NR, but this might negate the immediate value.
 // If the immediate value is negated, the second return value is true, otherwise always false.
 func (m *machine) getOperand_MaybeNegatedImm12_ER_SR_NR(def *backend.SSAValueDefinition, mode extMode) (op operand, negatedImm12 bool) {
-	if def.IsFromBlockParam() {
-		return operandNR(def.BlkParamVReg), false
+	if !def.IsFromInstr() {
+		return operandNR(m.compiler.VRegOf(def.V)), false
 	}
 
 	instr := def.Instr
@@ -193,7 +193,7 @@ func (m *machine) getOperand_MaybeNegatedImm12_ER_SR_NR(def *backend.SSAValueDef
 		}
 
 		signExtended := int64(c)
-		if def.SSAValue().Type().Bits() == 32 {
+		if def.V.Type().Bits() == 32 {
 			signExtended = (signExtended << 32) >> 32
 		}
 		negatedWithoutSign := -signExtended
@@ -209,8 +209,8 @@ func (m *machine) getOperand_MaybeNegatedImm12_ER_SR_NR(def *backend.SSAValueDef
 //
 // `mode` is used to extend the operand if the bit length is smaller than mode.bits().
 func (m *machine) getOperand_ER_SR_NR(def *backend.SSAValueDefinition, mode extMode) (op operand) {
-	if def.IsFromBlockParam() {
-		return operandNR(def.BlkParamVReg)
+	if !def.IsFromInstr() {
+		return operandNR(m.compiler.VRegOf(def.V))
 	}
 
 	if m.compiler.MatchInstr(def, ssa.OpcodeSExtend) || m.compiler.MatchInstr(def, ssa.OpcodeUExtend) {
@@ -252,8 +252,8 @@ func (m *machine) getOperand_ER_SR_NR(def *backend.SSAValueDefinition, mode extM
 //
 // `mode` is used to extend the operand if the bit length is smaller than mode.bits().
 func (m *machine) getOperand_SR_NR(def *backend.SSAValueDefinition, mode extMode) (op operand) {
-	if def.IsFromBlockParam() {
-		return operandNR(def.BlkParamVReg)
+	if !def.IsFromInstr() {
+		return operandNR(m.compiler.VRegOf(def.V))
 	}
 
 	if m.compiler.MatchInstr(def, ssa.OpcodeIshl) {
@@ -274,8 +274,8 @@ func (m *machine) getOperand_SR_NR(def *backend.SSAValueDefinition, mode extMode
 
 // getOperand_ShiftImm_NR returns an operand of either operandKindShiftImm or operandKindNR from the given value (defined by `def).
 func (m *machine) getOperand_ShiftImm_NR(def *backend.SSAValueDefinition, mode extMode, shiftBitWidth byte) (op operand) {
-	if def.IsFromBlockParam() {
-		return operandNR(def.BlkParamVReg)
+	if !def.IsFromInstr() {
+		return operandNR(m.compiler.VRegOf(def.V))
 	}
 
 	instr := def.Instr
@@ -291,26 +291,16 @@ func (m *machine) getOperand_ShiftImm_NR(def *backend.SSAValueDefinition, mode e
 // `mode` is used to extend the operand if the bit length is smaller than mode.bits().
 func (m *machine) getOperand_NR(def *backend.SSAValueDefinition, mode extMode) (op operand) {
 	var v regalloc.VReg
-	if def.IsFromBlockParam() {
-		v = def.BlkParamVReg
+	if def.IsFromInstr() && def.Instr.Constant() {
+		// We inline all the constant instructions so that we could reduce the register usage.
+		v = m.lowerConstant(def.Instr)
+		def.Instr.MarkLowered()
 	} else {
-		instr := def.Instr
-		if instr.Constant() {
-			// We inline all the constant instructions so that we could reduce the register usage.
-			v = m.lowerConstant(instr)
-			instr.MarkLowered()
-		} else {
-			if n := def.N; n == 0 {
-				v = m.compiler.VRegOf(instr.Return())
-			} else {
-				_, rs := instr.Returns()
-				v = m.compiler.VRegOf(rs[n-1])
-			}
-		}
+		v = m.compiler.VRegOf(def.V)
 	}
 
 	r := v
-	switch inBits := def.SSAValue().Type().Bits(); {
+	switch inBits := def.V.Type().Bits(); {
 	case mode == extModeNone:
 	case inBits == 32 && (mode == extModeZeroExtend32 || mode == extModeSignExtend32):
 	case inBits == 32 && mode == extModeZeroExtend64:
diff --git a/internal/engine/wazevo/backend/vdef.go b/internal/engine/wazevo/backend/vdef.go
index 0951f9ab..3c66a94a 100644
--- a/internal/engine/wazevo/backend/vdef.go
+++ b/internal/engine/wazevo/backend/vdef.go
@@ -1,22 +1,15 @@
 package backend
 
 import (
-	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
 	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
 )
 
 // SSAValueDefinition represents a definition of an SSA value.
+// TODO: this eventually should be deleted.
 type SSAValueDefinition struct {
-	// BlockParamValue is valid if Instr == nil
-	BlockParamValue ssa.Value
-
-	// BlkParamVReg is valid if Instr == nil
-	BlkParamVReg regalloc.VReg
-
+	V ssa.Value
 	// Instr is not nil if this is a definition from an instruction.
 	Instr *ssa.Instruction
-	// N is the index of the return value in the instr's return values list.
-	N int
 	// RefCount is the number of references to the result.
 	RefCount uint32
 }
@@ -24,20 +17,3 @@ type SSAValueDefinition struct {
 func (d *SSAValueDefinition) IsFromInstr() bool {
 	return d.Instr != nil
 }
-
-func (d *SSAValueDefinition) IsFromBlockParam() bool {
-	return d.Instr == nil
-}
-
-func (d *SSAValueDefinition) SSAValue() ssa.Value {
-	if d.IsFromBlockParam() {
-		return d.BlockParamValue
-	} else {
-		r, rs := d.Instr.Returns()
-		if d.N == 0 {
-			return r
-		} else {
-			return rs[d.N-1]
-		}
-	}
-}


Test patch:
diff --git a/internal/engine/wazevo/backend/isa/amd64/lower_mem_test.go b/internal/engine/wazevo/backend/isa/amd64/lower_mem_test.go
index 7f6d7460..1b3006c0 100644
--- a/internal/engine/wazevo/backend/isa/amd64/lower_mem_test.go
+++ b/internal/engine/wazevo/backend/isa/amd64/lower_mem_test.go
@@ -53,7 +53,8 @@ func TestMachine_lowerToAddressMode(t *testing.T) {
 				ptr = iadd.Return()
 				offset = 3
 				ctx.definitions[iconst1.Return()] = &backend.SSAValueDefinition{Instr: iconst1}
-				ctx.definitions[p] = &backend.SSAValueDefinition{BlockParamValue: p, BlkParamVReg: raxVReg}
+				ctx.vRegMap[p] = raxVReg
+				ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 				ctx.definitions[ptr] = &backend.SSAValueDefinition{Instr: iadd}
 				return
 			},
@@ -67,8 +68,10 @@ func TestMachine_lowerToAddressMode(t *testing.T) {
 				iadd := b.AllocateInstruction().AsIadd(p1, p2).Insert(b)
 				ptr = iadd.Return()
 				offset = 3
-				ctx.definitions[p1] = &backend.SSAValueDefinition{BlockParamValue: p1, BlkParamVReg: raxVReg}
-				ctx.definitions[p2] = &backend.SSAValueDefinition{BlockParamValue: p2, BlkParamVReg: rcxVReg}
+				ctx.vRegMap[p1] = raxVReg
+				ctx.definitions[p1] = &backend.SSAValueDefinition{V: p1}
+				ctx.vRegMap[p2] = rcxVReg
+				ctx.definitions[p2] = &backend.SSAValueDefinition{V: p2}
 				ctx.definitions[ptr] = &backend.SSAValueDefinition{Instr: iadd}
 				return
 			},
@@ -79,7 +82,8 @@ func TestMachine_lowerToAddressMode(t *testing.T) {
 			in: func(ctx *mockCompiler, b ssa.Builder, m *machine) (ptr ssa.Value, offset uint32) {
 				ptr = b.CurrentBlock().AddParam(b, ssa.TypeI64)
 				offset = 1 << 31
-				ctx.definitions[ptr] = &backend.SSAValueDefinition{BlockParamValue: ptr, BlkParamVReg: raxVReg}
+				ctx.vRegMap[ptr] = raxVReg
+				ctx.definitions[ptr] = &backend.SSAValueDefinition{V: ptr}
 				return
 			},
 			insts: []string{
@@ -109,7 +113,8 @@ func TestMachine_lowerToAddressMode(t *testing.T) {
 				p := b.CurrentBlock().AddParam(b, ssa.TypeI64)
 				iconst64 := b.AllocateInstruction().AsIconst64(2).Insert(b)
 				ishl := b.AllocateInstruction().AsIshl(p, iconst64.Return()).Insert(b)
-				ctx.definitions[p] = &backend.SSAValueDefinition{BlockParamValue: p, BlkParamVReg: raxVReg}
+				ctx.vRegMap[p] = raxVReg
+				ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 				ctx.definitions[iconst64.Return()] = &backend.SSAValueDefinition{Instr: iconst64}
 				ctx.definitions[ishl.Return()] = &backend.SSAValueDefinition{Instr: ishl}
 				return ishl.Return(), 1 << 30
@@ -127,8 +132,10 @@ func TestMachine_lowerToAddressMode(t *testing.T) {
 				const2 := b.AllocateInstruction().AsIconst64(2).Insert(b)
 				ishl := b.AllocateInstruction().AsIshl(p1, const2.Return()).Insert(b)
 				iadd := b.AllocateInstruction().AsIadd(p2, ishl.Return()).Insert(b)
-				ctx.definitions[p1] = &backend.SSAValueDefinition{BlockParamValue: p1, BlkParamVReg: raxVReg}
-				ctx.definitions[p2] = &backend.SSAValueDefinition{BlockParamValue: p2, BlkParamVReg: rcxVReg}
+				ctx.vRegMap[p1] = raxVReg
+				ctx.definitions[p1] = &backend.SSAValueDefinition{V: p1}
+				ctx.vRegMap[p2] = rcxVReg
+				ctx.definitions[p2] = &backend.SSAValueDefinition{V: p2}
 				ctx.definitions[const2.Return()] = &backend.SSAValueDefinition{Instr: const2}
 				ctx.definitions[ishl.Return()] = &backend.SSAValueDefinition{Instr: ishl}
 				ctx.definitions[iadd.Return()] = &backend.SSAValueDefinition{Instr: iadd}
@@ -181,7 +188,8 @@ func TestMachine_lowerAddendFromInstr(t *testing.T) {
 			name: "uextend const64",
 			in: func(ctx *mockCompiler, b ssa.Builder, m *machine) *ssa.Instruction {
 				p := b.CurrentBlock().AddParam(b, ssa.TypeI32)
-				ctx.definitions[p] = &backend.SSAValueDefinition{BlkParamVReg: raxVReg, BlockParamValue: p}
+				ctx.vRegMap[p] = raxVReg
+				ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 				return b.AllocateInstruction().AsUExtend(p, 32, 64).Insert(b)
 			},
 			exp: addend{raxVReg, 0, 0},
@@ -190,7 +198,8 @@ func TestMachine_lowerAddendFromInstr(t *testing.T) {
 			name: "uextend param i32",
 			in: func(ctx *mockCompiler, b ssa.Builder, m *machine) *ssa.Instruction {
 				p := b.CurrentBlock().AddParam(b, ssa.TypeI32)
-				ctx.definitions[p] = &backend.SSAValueDefinition{BlkParamVReg: raxVReg, BlockParamValue: p}
+				ctx.vRegMap[p] = raxVReg
+				ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 				return b.AllocateInstruction().AsUExtend(p, 32, 64).Insert(b)
 			},
 			exp: addend{raxVReg, 0, 0},
@@ -208,7 +217,8 @@ func TestMachine_lowerAddendFromInstr(t *testing.T) {
 			name: "sextend const64",
 			in: func(ctx *mockCompiler, b ssa.Builder, m *machine) *ssa.Instruction {
 				p := b.CurrentBlock().AddParam(b, ssa.TypeI32)
-				ctx.definitions[p] = &backend.SSAValueDefinition{BlkParamVReg: raxVReg, BlockParamValue: p}
+				ctx.vRegMap[p] = raxVReg
+				ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 				return b.AllocateInstruction().AsSExtend(p, 32, 64).Insert(b)
 			},
 			exp: addend{raxVReg, 0, 0},
@@ -217,7 +227,8 @@ func TestMachine_lowerAddendFromInstr(t *testing.T) {
 			name: "sextend param i32",
 			in: func(ctx *mockCompiler, b ssa.Builder, m *machine) *ssa.Instruction {
 				p := b.CurrentBlock().AddParam(b, ssa.TypeI32)
-				ctx.definitions[p] = &backend.SSAValueDefinition{BlkParamVReg: raxVReg, BlockParamValue: p}
+				ctx.vRegMap[p] = raxVReg
+				ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 				return b.AllocateInstruction().AsSExtend(p, 32, 64).Insert(b)
 			},
 			exp: addend{raxVReg, 0, 0},
diff --git a/internal/engine/wazevo/backend/isa/amd64/machine_test.go b/internal/engine/wazevo/backend/isa/amd64/machine_test.go
index 5614b45c..b02a5bd7 100644
--- a/internal/engine/wazevo/backend/isa/amd64/machine_test.go
+++ b/internal/engine/wazevo/backend/isa/amd64/machine_test.go
@@ -46,7 +46,8 @@ func TestMachine_getOperand_Reg(t *testing.T) {
 		{
 			name: "block param",
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) *backend.SSAValueDefinition {
-				return &backend.SSAValueDefinition{BlkParamVReg: raxVReg, Instr: nil, N: 0}
+				ctx.vRegMap[1234] = raxVReg
+				return &backend.SSAValueDefinition{V: 1234, Instr: nil}
 			},
 			exp: newOperandReg(raxVReg),
 		},
@@ -58,7 +59,7 @@ func TestMachine_getOperand_Reg(t *testing.T) {
 				instr.AsIconst32(0xf00000f)
 				builder.InsertInstruction(instr)
 				ctx.vRegCounter = 99
-				return &backend.SSAValueDefinition{Instr: instr, N: 0}
+				return &backend.SSAValueDefinition{Instr: instr}
 			},
 			exp:          newOperandReg(regalloc.VReg(100).SetRegType(regalloc.RegTypeInt)),
 			instructions: []string{"movl $251658255, %r100d?"},
@@ -73,7 +74,7 @@ func TestMachine_getOperand_Reg(t *testing.T) {
 				builder.InsertInstruction(c)
 				r := c.Return()
 				ctx.vRegMap[r] = regalloc.VReg(50)
-				return &backend.SSAValueDefinition{Instr: c, N: 0}
+				return &backend.SSAValueDefinition{V: r}
 			},
 			exp: newOperandReg(regalloc.VReg(50)),
 		},
@@ -87,7 +88,7 @@ func TestMachine_getOperand_Reg(t *testing.T) {
 				builder.InsertInstruction(c)
 				_, rs := c.Returns()
 				ctx.vRegMap[rs[1]] = regalloc.VReg(50)
-				return &backend.SSAValueDefinition{Instr: c, N: 2}
+				return &backend.SSAValueDefinition{V: rs[1]}
 			},
 			exp: newOperandReg(regalloc.VReg(50)),
 		},
@@ -112,7 +113,8 @@ func TestMachine_getOperand_Imm32_Reg(t *testing.T) {
 		{
 			name: "block param falls back to getOperand_Reg",
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) *backend.SSAValueDefinition {
-				return &backend.SSAValueDefinition{BlkParamVReg: raxVReg, Instr: nil, N: 0}
+				ctx.vRegMap[1234] = raxVReg
+				return &backend.SSAValueDefinition{V: 1234, Instr: nil}
 			},
 			exp: newOperandReg(raxVReg),
 		},
@@ -124,7 +126,7 @@ func TestMachine_getOperand_Imm32_Reg(t *testing.T) {
 				builder.InsertInstruction(instr)
 				ctx.vRegCounter = 99
 				ctx.currentGID = 0xff // const can be merged anytime, regardless of the group id.
-				return &backend.SSAValueDefinition{Instr: instr, N: 0}
+				return &backend.SSAValueDefinition{Instr: instr}
 			},
 			exp: newOperandImm32(0xf00000f),
 		},
@@ -155,7 +157,8 @@ func Test_machine_getOperand_Mem_Imm32_Reg(t *testing.T) {
 		{
 			name: "block param falls back to getOperand_Imm32_Reg",
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) *backend.SSAValueDefinition {
-				return &backend.SSAValueDefinition{BlkParamVReg: raxVReg, Instr: nil, N: 0}
+				ctx.vRegMap[1234] = raxVReg
+				return &backend.SSAValueDefinition{V: 1234, Instr: nil}
 			},
 			exp: newOperandReg(raxVReg),
 		},
@@ -164,10 +167,11 @@ func Test_machine_getOperand_Mem_Imm32_Reg(t *testing.T) {
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) *backend.SSAValueDefinition {
 				blk := builder.CurrentBlock()
 				ptr := blk.AddParam(builder, ssa.TypeI64)
-				ctx.definitions[ptr] = &backend.SSAValueDefinition{BlockParamValue: ptr, BlkParamVReg: raxVReg}
+				ctx.vRegMap[ptr] = raxVReg
+				ctx.definitions[ptr] = &backend.SSAValueDefinition{V: ptr}
 				instr := builder.AllocateInstruction()
 				instr.AsLoad(ptr, 123, ssa.TypeI64).Insert(builder)
-				return &backend.SSAValueDefinition{Instr: instr, N: 0}
+				return &backend.SSAValueDefinition{Instr: instr}
 			},
 			exp: newOperandMem(newAmodeImmReg(123, raxVReg)),
 		},
@@ -178,7 +182,7 @@ func Test_machine_getOperand_Mem_Imm32_Reg(t *testing.T) {
 				instr := builder.AllocateInstruction()
 				instr.AsLoad(iconst.Return(), 123, ssa.TypeI64).Insert(builder)
 				ctx.definitions[iconst.Return()] = &backend.SSAValueDefinition{Instr: iconst}
-				return &backend.SSAValueDefinition{Instr: instr, N: 0}
+				return &backend.SSAValueDefinition{Instr: instr}
 			},
 			instructions: []string{
 				"movabsq $579, %r1?", // r1 := 123+456
@@ -197,7 +201,7 @@ func Test_machine_getOperand_Mem_Imm32_Reg(t *testing.T) {
 				ctx.definitions[uextend.Return()] = &backend.SSAValueDefinition{Instr: uextend}
 				ctx.definitions[iconst.Return()] = &backend.SSAValueDefinition{Instr: iconst}
 
-				return &backend.SSAValueDefinition{Instr: instr, N: 0}
+				return &backend.SSAValueDefinition{Instr: instr}
 			},
 			instructions: []string{
 				fmt.Sprintf("movabsq $%d, %%r1?", 0xffffff+123),
@@ -216,7 +220,7 @@ func Test_machine_getOperand_Mem_Imm32_Reg(t *testing.T) {
 				ctx.definitions[uextend.Return()] = &backend.SSAValueDefinition{Instr: uextend}
 				ctx.definitions[iconst.Return()] = &backend.SSAValueDefinition{Instr: iconst}
 
-				return &backend.SSAValueDefinition{Instr: instr, N: 0}
+				return &backend.SSAValueDefinition{Instr: instr}
 			},
 			instructions: []string{
 				fmt.Sprintf("movabsq $%d, %%r1?", 456+123),
@@ -233,11 +237,12 @@ func Test_machine_getOperand_Mem_Imm32_Reg(t *testing.T) {
 				instr := builder.AllocateInstruction()
 				instr.AsLoad(iadd.Return(), 789, ssa.TypeI64).Insert(builder)
 
-				ctx.definitions[p] = &backend.SSAValueDefinition{BlockParamValue: p, BlkParamVReg: raxVReg}
+				ctx.vRegMap[p] = raxVReg
+				ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 				ctx.definitions[iconst.Return()] = &backend.SSAValueDefinition{Instr: iconst}
 				ctx.definitions[iadd.Return()] = &backend.SSAValueDefinition{Instr: iadd}
 
-				return &backend.SSAValueDefinition{Instr: instr, N: 0}
+				return &backend.SSAValueDefinition{Instr: instr}
 			},
 			exp: newOperandMem(newAmodeImmReg(456+789, raxVReg)),
 		},
@@ -255,7 +260,7 @@ func Test_machine_getOperand_Mem_Imm32_Reg(t *testing.T) {
 				ctx.definitions[iconst2.Return()] = &backend.SSAValueDefinition{Instr: iconst2}
 				ctx.definitions[iadd.Return()] = &backend.SSAValueDefinition{Instr: iadd}
 
-				return &backend.SSAValueDefinition{Instr: instr, N: 0}
+				return &backend.SSAValueDefinition{Instr: instr}
 			},
 			instructions: []string{
 				fmt.Sprintf("movabsq $%d, %%r1?", 123+456+789),
@@ -361,7 +366,8 @@ L2:
 			p := b.CurrentBlock().AddParam(b, tc.typ)
 			m.cpuFeatures = tc.cpuFlags
 
-			ctx.definitions[p] = &backend.SSAValueDefinition{BlockParamValue: p, BlkParamVReg: raxVReg}
+			ctx.vRegMap[p] = raxVReg
+			ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 			ctx.vRegMap[0] = rcxVReg
 			instr := &ssa.Instruction{}
 			instr.AsClz(p)
@@ -434,7 +440,8 @@ L2:
 			p := b.CurrentBlock().AddParam(b, tc.typ)
 			m.cpuFeatures = tc.cpuFlags
 
-			ctx.definitions[p] = &backend.SSAValueDefinition{BlockParamValue: p, BlkParamVReg: raxVReg}
+			ctx.vRegMap[p] = raxVReg
+			ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 			ctx.vRegMap[0] = rcxVReg
 			instr := &ssa.Instruction{}
 			instr.AsCtz(p)
diff --git a/internal/engine/wazevo/backend/isa/arm64/lower_instr_operands_test.go b/internal/engine/wazevo/backend/isa/arm64/lower_instr_operands_test.go
index 11494652..ba7520fb 100644
--- a/internal/engine/wazevo/backend/isa/arm64/lower_instr_operands_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/lower_instr_operands_test.go
@@ -40,7 +40,8 @@ func TestMachine_getOperand_NR(t *testing.T) {
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) (def *backend.SSAValueDefinition, mode extMode) {
 				blk := builder.CurrentBlock()
 				v := blk.AddParam(builder, ssa.TypeI64)
-				def = &backend.SSAValueDefinition{BlkParamVReg: regToVReg(x4), BlockParamValue: v}
+				ctx.vRegMap[v] = regToVReg(x4)
+				def = &backend.SSAValueDefinition{V: v}
 				return def, extModeZeroExtend64
 			},
 			exp: operandNR(regToVReg(x4)),
@@ -50,7 +51,8 @@ func TestMachine_getOperand_NR(t *testing.T) {
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) (def *backend.SSAValueDefinition, mode extMode) {
 				blk := builder.CurrentBlock()
 				v := blk.AddParam(builder, ssa.TypeI32)
-				def = &backend.SSAValueDefinition{BlkParamVReg: regToVReg(x4), BlockParamValue: v}
+				ctx.vRegMap[v] = regToVReg(x4)
+				def = &backend.SSAValueDefinition{V: v}
 				return def, extModeZeroExtend64
 			},
 			exp:          operandNR(regalloc.VReg(1).SetRegType(regalloc.RegTypeInt)),
@@ -61,7 +63,8 @@ func TestMachine_getOperand_NR(t *testing.T) {
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) (def *backend.SSAValueDefinition, mode extMode) {
 				blk := builder.CurrentBlock()
 				v := blk.AddParam(builder, ssa.TypeI32)
-				def = &backend.SSAValueDefinition{BlkParamVReg: regToVReg(x4), BlockParamValue: v}
+				ctx.vRegMap[v] = regToVReg(x4)
+				def = &backend.SSAValueDefinition{V: v}
 				return def, extModeSignExtend64
 			},
 			exp:          operandNR(regalloc.VReg(1).SetRegType(regalloc.RegTypeInt)),
@@ -73,7 +76,7 @@ func TestMachine_getOperand_NR(t *testing.T) {
 				instr := builder.AllocateInstruction()
 				instr.AsIconst32(0xf00000f)
 				builder.InsertInstruction(instr)
-				def = &backend.SSAValueDefinition{Instr: instr, N: 0}
+				def = &backend.SSAValueDefinition{Instr: instr, V: instr.Return()}
 				ctx.vRegCounter = 99
 				return
 			},
@@ -93,7 +96,7 @@ func TestMachine_getOperand_NR(t *testing.T) {
 				builder.InsertInstruction(c)
 				_, rs := c.Returns()
 				ctx.vRegMap[rs[1]] = regalloc.VReg(50)
-				def = &backend.SSAValueDefinition{Instr: c, N: 2}
+				def = &backend.SSAValueDefinition{Instr: c, V: rs[1]}
 				return
 			},
 			exp: operandNR(regalloc.VReg(50)),
@@ -132,14 +135,16 @@ func TestMachine_getOperand_SR_NR(t *testing.T) {
 		ishl.AsIshl(addResult, amountVal)
 		builder.InsertInstruction(ishl)
 
-		ctx.definitions[p1] = &backend.SSAValueDefinition{BlkParamVReg: regalloc.VReg(1), BlockParamValue: p1}
-		ctx.definitions[p2] = &backend.SSAValueDefinition{BlkParamVReg: regalloc.VReg(2), BlockParamValue: p2}
-		ctx.definitions[addResult] = &backend.SSAValueDefinition{Instr: add, N: 0}
-		ctx.definitions[amountVal] = &backend.SSAValueDefinition{Instr: amount, N: 0}
+		ctx.vRegMap[p1] = regalloc.VReg(1)
+		ctx.definitions[p1] = &backend.SSAValueDefinition{V: p1}
+		ctx.vRegMap[p2] = regalloc.VReg(2)
+		ctx.definitions[p2] = &backend.SSAValueDefinition{V: p2}
+		ctx.definitions[addResult] = &backend.SSAValueDefinition{Instr: add, V: addResult}
+		ctx.definitions[amountVal] = &backend.SSAValueDefinition{Instr: amount, V: amountVal}
 
 		ctx.vRegMap[addResult] = regalloc.VReg(1234)
 		ctx.vRegMap[ishl.Return()] = regalloc.VReg(10)
-		def = &backend.SSAValueDefinition{Instr: ishl, N: 0}
+		def = &backend.SSAValueDefinition{Instr: ishl, V: ishl.Return()}
 		mode = extModeNone
 		verify = func(t *testing.T) {
 			require.True(t, ishl.Lowered())
@@ -159,7 +164,8 @@ func TestMachine_getOperand_SR_NR(t *testing.T) {
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) (def *backend.SSAValueDefinition, mode extMode, verify func(t *testing.T)) {
 				blk := builder.CurrentBlock()
 				v := blk.AddParam(builder, ssa.TypeI64)
-				def = &backend.SSAValueDefinition{BlkParamVReg: regToVReg(x4), BlockParamValue: v}
+				ctx.vRegMap[v] = regToVReg(x4)
+				def = &backend.SSAValueDefinition{V: v}
 				return def, extModeNone, func(t *testing.T) {}
 			},
 			exp: operandNR(regToVReg(x4)),
@@ -181,13 +187,16 @@ func TestMachine_getOperand_SR_NR(t *testing.T) {
 				ishl.AsIshl(addResult, p3)
 				builder.InsertInstruction(ishl)
 
-				ctx.definitions[p1] = &backend.SSAValueDefinition{BlkParamVReg: regalloc.VReg(1), BlockParamValue: p1}
-				ctx.definitions[p2] = &backend.SSAValueDefinition{BlkParamVReg: regalloc.VReg(2), BlockParamValue: p2}
-				ctx.definitions[p3] = &backend.SSAValueDefinition{BlkParamVReg: regalloc.VReg(3), BlockParamValue: p3}
-				ctx.definitions[addResult] = &backend.SSAValueDefinition{Instr: add, N: 0}
+				ctx.vRegMap[p1] = regalloc.VReg(1)
+				ctx.definitions[p1] = &backend.SSAValueDefinition{V: p1}
+				ctx.vRegMap[p2] = regalloc.VReg(2)
+				ctx.definitions[p2] = &backend.SSAValueDefinition{V: p2}
+				ctx.vRegMap[p3] = regalloc.VReg(3)
+				ctx.definitions[p3] = &backend.SSAValueDefinition{V: p3}
+				ctx.definitions[addResult] = &backend.SSAValueDefinition{Instr: add, V: addResult}
 				ctx.vRegMap[addResult] = regalloc.VReg(1234) // whatever is fine.
 				ctx.vRegMap[ishl.Return()] = regalloc.VReg(10)
-				def = &backend.SSAValueDefinition{Instr: ishl, N: 0}
+				def = &backend.SSAValueDefinition{Instr: ishl, V: ishl.Return()}
 				return def, extModeNone, func(t *testing.T) {}
 			},
 			exp: operandNR(regalloc.VReg(10)),
@@ -221,14 +230,16 @@ func TestMachine_getOperand_SR_NR(t *testing.T) {
 				ishl.AsIshl(addResult, amountVal)
 				builder.InsertInstruction(ishl)
 
-				ctx.definitions[p1] = &backend.SSAValueDefinition{BlkParamVReg: regalloc.VReg(1), BlockParamValue: p1}
-				ctx.definitions[p2] = &backend.SSAValueDefinition{BlkParamVReg: regalloc.VReg(2), BlockParamValue: p2}
-				ctx.definitions[addResult] = &backend.SSAValueDefinition{Instr: add, N: 0}
-				ctx.definitions[amountVal] = &backend.SSAValueDefinition{Instr: amount, N: 0}
+				ctx.vRegMap[p1] = regalloc.VReg(1)
+				ctx.definitions[p1] = &backend.SSAValueDefinition{V: p1}
+				ctx.vRegMap[p2] = regalloc.VReg(2)
+				ctx.definitions[p2] = &backend.SSAValueDefinition{V: p2}
+				ctx.definitions[addResult] = &backend.SSAValueDefinition{Instr: add, V: addResult}
+				ctx.definitions[amountVal] = &backend.SSAValueDefinition{Instr: amount, V: amountVal}
 
 				ctx.vRegMap[addResult] = regalloc.VReg(1234)
 				ctx.vRegMap[ishl.Return()] = regalloc.VReg(10)
-				def = &backend.SSAValueDefinition{Instr: ishl, N: 0}
+				def = &backend.SSAValueDefinition{Instr: ishl}
 				mode = extModeNone
 				verify = func(t *testing.T) {
 					require.True(t, ishl.Lowered())
@@ -254,11 +265,11 @@ func TestMachine_getOperand_SR_NR(t *testing.T) {
 				ishl.AsIshl(target.Return(), amountVal)
 				builder.InsertInstruction(ishl)
 
-				ctx.definitions[targetVal] = &backend.SSAValueDefinition{Instr: target, N: 0}
-				ctx.definitions[amountVal] = &backend.SSAValueDefinition{Instr: amount, N: 0}
+				ctx.definitions[targetVal] = &backend.SSAValueDefinition{Instr: target, V: targetVal}
+				ctx.definitions[amountVal] = &backend.SSAValueDefinition{Instr: amount, V: amountVal}
 				ctx.vRegMap[targetVal] = regalloc.VReg(1234)
 				ctx.vRegMap[ishl.Return()] = regalloc.VReg(10)
-				def = &backend.SSAValueDefinition{Instr: ishl, N: 0}
+				def = &backend.SSAValueDefinition{Instr: ishl}
 				mode = extModeNone
 				verify = func(t *testing.T) {
 					require.True(t, ishl.Lowered())
@@ -323,7 +334,8 @@ func TestMachine_getOperand_ER_SR_NR(t *testing.T) {
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) (def *backend.SSAValueDefinition, mode extMode, verify func(t *testing.T)) {
 				blk := builder.CurrentBlock()
 				v := blk.AddParam(builder, ssa.TypeI64)
-				def = &backend.SSAValueDefinition{BlkParamVReg: regToVReg(x4), BlockParamValue: v}
+				ctx.vRegMap[v] = regToVReg(x4)
+				def = &backend.SSAValueDefinition{V: v}
 				return def, extModeZeroExtend64, func(t *testing.T) {}
 			},
 			exp: operandNR(regToVReg(x4)),
@@ -359,9 +371,9 @@ func TestMachine_getOperand_ER_SR_NR(t *testing.T) {
 					}
 					builder.InsertInstruction(ext)
 					extArg := ext.Arg()
-					ctx.vRegMap[ext.Arg()] = regalloc.VReg(10)
-					ctx.definitions[v] = &backend.SSAValueDefinition{BlkParamVReg: regalloc.VReg(10), BlockParamValue: extArg}
-					def = &backend.SSAValueDefinition{Instr: ext, N: 0}
+					ctx.vRegMap[extArg] = regalloc.VReg(10)
+					ctx.definitions[v] = &backend.SSAValueDefinition{V: extArg}
+					def = &backend.SSAValueDefinition{Instr: ext, V: ext.Return()}
 					return def, extModeNone, func(t *testing.T) {
 						require.True(t, ext.Lowered())
 					}
@@ -571,16 +583,11 @@ func TestMachine_getOperand_ER_SR_NR(t *testing.T) {
 						ctx.vRegMap[ext.Return()] = resultVReg
 						if c.extArgConst {
 							iconst := builder.AllocateInstruction().AsIconst32(0xffff).Insert(builder)
-							m.compiler.(*mockCompiler).definitions[extArg] = &backend.SSAValueDefinition{
-								Instr: iconst,
-							}
+							m.compiler.(*mockCompiler).definitions[extArg] = &backend.SSAValueDefinition{Instr: iconst, V: iconst.Return()}
 						} else {
-							m.compiler.(*mockCompiler).definitions[extArg] = &backend.SSAValueDefinition{
-								BlkParamVReg:    argVReg,
-								BlockParamValue: extArg,
-							}
+							m.compiler.(*mockCompiler).definitions[extArg] = &backend.SSAValueDefinition{V: extArg}
 						}
-						def = &backend.SSAValueDefinition{Instr: ext, N: 0}
+						def = &backend.SSAValueDefinition{Instr: ext}
 						return def, c.mode, func(t *testing.T) {
 							require.Equal(t, c.lowered, ext.Lowered())
 						}
@@ -605,7 +612,8 @@ func TestMachine_getOperand_Imm12_ER_SR_NR(t *testing.T) {
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) (def *backend.SSAValueDefinition, mode extMode) {
 				blk := builder.CurrentBlock()
 				v := blk.AddParam(builder, ssa.TypeI64)
-				def = &backend.SSAValueDefinition{BlkParamVReg: regToVReg(x4), BlockParamValue: v}
+				ctx.vRegMap[v] = regToVReg(x4)
+				def = &backend.SSAValueDefinition{V: v}
 				return def, extModeZeroExtend64
 			},
 			exp: operandNR(regToVReg(x4)),
@@ -616,7 +624,7 @@ func TestMachine_getOperand_Imm12_ER_SR_NR(t *testing.T) {
 				cinst := builder.AllocateInstruction()
 				cinst.AsIconst32(0xfff)
 				builder.InsertInstruction(cinst)
-				def = &backend.SSAValueDefinition{Instr: cinst, N: 0}
+				def = &backend.SSAValueDefinition{Instr: cinst}
 				ctx.currentGID = 0xff // const can be merged anytime, regardless of the group id.
 				return
 			},
@@ -628,7 +636,7 @@ func TestMachine_getOperand_Imm12_ER_SR_NR(t *testing.T) {
 				cinst := builder.AllocateInstruction()
 				cinst.AsIconst32(0xabc_000)
 				builder.InsertInstruction(cinst)
-				def = &backend.SSAValueDefinition{Instr: cinst, N: 0}
+				def = &backend.SSAValueDefinition{Instr: cinst}
 				ctx.currentGID = 0xff // const can be merged anytime, regardless of the group id.
 				return
 			},
@@ -658,7 +666,8 @@ func TestMachine_getOperand_MaybeNegatedImm12_ER_SR_NR(t *testing.T) {
 			setup: func(ctx *mockCompiler, builder ssa.Builder, m *machine) (def *backend.SSAValueDefinition, mode extMode) {
 				blk := builder.CurrentBlock()
 				v := blk.AddParam(builder, ssa.TypeI64)
-				def = &backend.SSAValueDefinition{BlkParamVReg: regToVReg(x4), BlockParamValue: v}
+				ctx.vRegMap[v] = regToVReg(x4)
+				def = &backend.SSAValueDefinition{V: v}
 				return def, extModeZeroExtend64
 			},
 			exp: operandNR(regToVReg(x4)),
@@ -669,7 +678,7 @@ func TestMachine_getOperand_MaybeNegatedImm12_ER_SR_NR(t *testing.T) {
 				cinst := builder.AllocateInstruction()
 				cinst.AsIconst32(0xfff)
 				builder.InsertInstruction(cinst)
-				def = &backend.SSAValueDefinition{Instr: cinst, N: 0}
+				def = &backend.SSAValueDefinition{Instr: cinst}
 				ctx.currentGID = 0xff // const can be merged anytime, regardless of the group id.
 				return
 			},
@@ -682,7 +691,7 @@ func TestMachine_getOperand_MaybeNegatedImm12_ER_SR_NR(t *testing.T) {
 				cinst := builder.AllocateInstruction()
 				cinst.AsIconst32(uint32(c))
 				builder.InsertInstruction(cinst)
-				def = &backend.SSAValueDefinition{Instr: cinst, N: 0}
+				def = &backend.SSAValueDefinition{Instr: cinst, V: cinst.Return()}
 				ctx.currentGID = 0xff // const can be merged anytime, regardless of the group id.
 				return
 			},
@@ -695,7 +704,7 @@ func TestMachine_getOperand_MaybeNegatedImm12_ER_SR_NR(t *testing.T) {
 				cinst := builder.AllocateInstruction()
 				cinst.AsIconst32(0xabc_000)
 				builder.InsertInstruction(cinst)
-				def = &backend.SSAValueDefinition{Instr: cinst, N: 0}
+				def = &backend.SSAValueDefinition{Instr: cinst}
 				ctx.currentGID = 0xff // const can be merged anytime, regardless of the group id.
 				return
 			},
@@ -708,7 +717,7 @@ func TestMachine_getOperand_MaybeNegatedImm12_ER_SR_NR(t *testing.T) {
 				cinst := builder.AllocateInstruction()
 				cinst.AsIconst32(uint32(c))
 				builder.InsertInstruction(cinst)
-				def = &backend.SSAValueDefinition{Instr: cinst, N: 0}
+				def = &backend.SSAValueDefinition{Instr: cinst, V: cinst.Return()}
 				ctx.currentGID = 0xff // const can be merged anytime, regardless of the group id.
 				return
 			},
diff --git a/internal/engine/wazevo/backend/isa/arm64/lower_instr_test.go b/internal/engine/wazevo/backend/isa/arm64/lower_instr_test.go
index 524811d7..9b8858a3 100644
--- a/internal/engine/wazevo/backend/isa/arm64/lower_instr_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/lower_instr_test.go
@@ -46,8 +46,8 @@ func TestMachine_LowerConditionalBranch(t *testing.T) {
 		cmpVal := cmpInstr.Return()
 		ctx.vRegMap[cmpVal] = 3
 
-		ctx.definitions[val1] = &backend.SSAValueDefinition{BlkParamVReg: ctx.vRegMap[val1], BlockParamValue: val1}
-		ctx.definitions[val2] = &backend.SSAValueDefinition{BlkParamVReg: ctx.vRegMap[val2], BlockParamValue: val2}
+		ctx.definitions[val1] = &backend.SSAValueDefinition{V: val1}
+		ctx.definitions[val2] = &backend.SSAValueDefinition{V: val2}
 		ctx.definitions[cmpVal] = &backend.SSAValueDefinition{Instr: cmpInstr}
 		b := builder.AllocateInstruction()
 		if brz {
@@ -74,7 +74,7 @@ func TestMachine_LowerConditionalBranch(t *testing.T) {
 		icmp.AsIcmp(v1, v2, ssa.IntegerCmpCondEqual)
 		builder.InsertInstruction(icmp)
 		icmpVal := icmp.Return()
-		ctx.definitions[v1] = &backend.SSAValueDefinition{BlkParamVReg: intToVReg(1), BlockParamValue: v1}
+		ctx.definitions[v1] = &backend.SSAValueDefinition{V: v1}
 		ctx.definitions[v2] = &backend.SSAValueDefinition{Instr: iconst}
 		ctx.definitions[icmpVal] = &backend.SSAValueDefinition{Instr: icmp}
 		ctx.vRegMap[v1], ctx.vRegMap[v2], ctx.vRegMap[icmpVal] = intToVReg(1), intToVReg(2), intToVReg(3)
@@ -105,7 +105,7 @@ func TestMachine_LowerConditionalBranch(t *testing.T) {
 				icmp.AsIcmp(v1, v2, ssa.IntegerCmpCondEqual)
 				builder.InsertInstruction(icmp)
 				icmpVal := icmp.Return()
-				ctx.definitions[icmpVal] = &backend.SSAValueDefinition{Instr: icmp}
+				ctx.definitions[icmpVal] = &backend.SSAValueDefinition{Instr: icmp, V: icmpVal}
 				ctx.vRegMap[v1], ctx.vRegMap[v2], ctx.vRegMap[icmpVal] = intToVReg(1), intToVReg(2), intToVReg(3)
 
 				brz := builder.AllocateInstruction()
diff --git a/internal/engine/wazevo/backend/isa/arm64/lower_mem_test.go b/internal/engine/wazevo/backend/isa/arm64/lower_mem_test.go
index e7a054d7..2dce0633 100644
--- a/internal/engine/wazevo/backend/isa/arm64/lower_mem_test.go
+++ b/internal/engine/wazevo/backend/isa/arm64/lower_mem_test.go
@@ -296,7 +296,8 @@ func TestMachine_collectAddends(t *testing.T) {
 	v1000, v2000 := regalloc.VReg(1000).SetRegType(regalloc.RegTypeInt), regalloc.VReg(2000).SetRegType(regalloc.RegTypeInt)
 	addParam := func(ctx *mockCompiler, b ssa.Builder, typ ssa.Type) ssa.Value {
 		p := b.CurrentBlock().AddParam(b, typ)
-		ctx.definitions[p] = &backend.SSAValueDefinition{BlockParamValue: p, BlkParamVReg: v1000}
+		ctx.vRegMap[p] = v1000
+		ctx.definitions[p] = &backend.SSAValueDefinition{V: p}
 		return p
 	}
 	insertI32Const := func(m *mockCompiler, b ssa.Builder, v uint32) *ssa.Instruction {
@@ -310,14 +311,14 @@ func TestMachine_collectAddends(t *testing.T) {
 		inst := b.AllocateInstruction()
 		inst.AsIconst64(v)
 		b.InsertInstruction(inst)
-		m.definitions[inst.Return()] = &backend.SSAValueDefinition{Instr: inst}
+		m.definitions[inst.Return()] = &backend.SSAValueDefinition{Instr: inst, V: inst.Return()}
 		return inst
 	}
 	insertIadd := func(m *mockCompiler, b ssa.Builder, lhs, rhs ssa.Value) *ssa.Instruction {
 		inst := b.AllocateInstruction()
 		inst.AsIadd(lhs, rhs)
 		b.InsertInstruction(inst)
-		m.definitions[inst.Return()] = &backend.SSAValueDefinition{Instr: inst}
+		m.definitions[inst.Return()] = &backend.SSAValueDefinition{Instr: inst, V: inst.Return()}
 		return inst
 	}
 	insertExt := func(m *mockCompiler, b ssa.Builder, v ssa.Value, from, to byte, signed bool) *ssa.Instruction {
@@ -328,7 +329,7 @@ func TestMachine_collectAddends(t *testing.T) {
 			inst.AsUExtend(v, from, to)
 		}
 		b.InsertInstruction(inst)
-		m.definitions[inst.Return()] = &backend.SSAValueDefinition{Instr: inst}
+		m.definitions[inst.Return()] = &backend.SSAValueDefinition{Instr: inst, V: v}
 		return inst
 	}