Repository: tetratelabs/wazero
Pull request #1388 (2023-04-21 02:11:03)

asm/amd64: uses enum for operand types
counterpart for #1378 

```
goos: linux
goarch: amd64
pkg: github.com/tetratelabs/wazero/internal/integration_test/bench
cpu: AMD Ryzen 9 3950X 16-Core Processor
                                    │   old.txt   │              new.txt              │
                                    │   sec/op    │   sec/op     vs base              │
Compilation/without_extern_cache-32   3.907m ± 1%   3.855m ± 1%  -1.34% (p=0.038 n=7)
Compilation_sqlite3/compiler-32       426.7m ± 4%   398.2m ± 1%  -6.67% (p=0.001 n=7)
geomean                               40.83m        39.18m       -4.04%

                                    │   old.txt    │              new.txt               │
                                    │     B/op     │     B/op      vs base              │
Compilation/without_extern_cache-32   664.4Ki ± 0%   664.5Ki ± 0%       ~ (p=0.053 n=7)
Compilation_sqlite3/compiler-32       49.40Mi ± 0%   49.40Mi ± 0%       ~ (p=0.456 n=7)
geomean                               5.661Mi        5.662Mi       +0.01%

                                    │   old.txt   │              new.txt              │
                                    │  allocs/op  │  allocs/op   vs base              │
Compilation/without_extern_cache-32    852.0 ± 0%    852.0 ± 0%       ~ (p=1.000 n=7)
Compilation_sqlite3/compiler-32       28.70k ± 0%   28.70k ± 0%       ~ (p=0.729 n=7)
geomean                               4.945k        4.945k       +0.00%
```


Patch:
diff --git a/internal/asm/amd64/impl.go b/internal/asm/amd64/impl.go
index 4cfa2b4d..fa28269a 100644
--- a/internal/asm/amd64/impl.go
+++ b/internal/asm/amd64/impl.go
@@ -164,62 +164,60 @@ func (n *nodeImpl) String() (ret string) {
 	return
 }
 
-// operandType represents where an operand is placed for an instruction.
-// Note: this is almost the same as obj.AddrType in GO assembler.
-type operandType byte
+type operandTypes byte
 
 const (
-	operandTypeNone operandType = iota
-	operandTypeRegister
-	operandTypeMemory
-	operandTypeConst
-	operandTypeStaticConst
-	operandTypeBranch
+	operandTypesNoneToNone operandTypes = iota
+	operandTypesNoneToRegister
+	operandTypesNoneToMemory
+	operandTypesNoneToBranch
+	operandTypesRegisterToNone
+	operandTypesRegisterToRegister
+	operandTypesRegisterToMemory
+	operandTypesRegisterToConst
+	operandTypesMemoryToRegister
+	operandTypesMemoryToConst
+	operandTypesConstToRegister
+	operandTypesConstToMemory
+	operandTypesStaticConstToRegister
+	operandTypesRegisterToStaticConst
 )
 
-func (o operandType) String() (ret string) {
+// String implements fmt.Stringer
+func (o operandTypes) String() (ret string) {
 	switch o {
-	case operandTypeNone:
-		ret = "none"
-	case operandTypeRegister:
-		ret = "register"
-	case operandTypeMemory:
-		ret = "memory"
-	case operandTypeConst:
-		ret = "const"
-	case operandTypeBranch:
-		ret = "branch"
-	case operandTypeStaticConst:
-		ret = "static-const"
+	case operandTypesNoneToNone:
+		ret = "NoneToNone"
+	case operandTypesNoneToRegister:
+		ret = "NoneToRegister"
+	case operandTypesNoneToMemory:
+		ret = "NoneToMemory"
+	case operandTypesNoneToBranch:
+		ret = "NoneToBranch"
+	case operandTypesRegisterToNone:
+		ret = "RegisterToNone"
+	case operandTypesRegisterToRegister:
+		ret = "RegisterToRegister"
+	case operandTypesRegisterToMemory:
+		ret = "RegisterToMemory"
+	case operandTypesRegisterToConst:
+		ret = "RegisterToConst"
+	case operandTypesMemoryToRegister:
+		ret = "MemoryToRegister"
+	case operandTypesMemoryToConst:
+		ret = "MemoryToConst"
+	case operandTypesConstToRegister:
+		ret = "ConstToRegister"
+	case operandTypesConstToMemory:
+		ret = "ConstToMemory"
+	case operandTypesStaticConstToRegister:
+		ret = "StaticConstToRegister"
+	case operandTypesRegisterToStaticConst:
+		ret = "RegisterToStaticConst"
 	}
 	return
 }
 
-// operandTypes represents the only combinations of two operandTypes used by wazero
-type operandTypes struct{ src, dst operandType }
-
-var (
-	operandTypesNoneToNone            = operandTypes{operandTypeNone, operandTypeNone}
-	operandTypesNoneToRegister        = operandTypes{operandTypeNone, operandTypeRegister}
-	operandTypesNoneToMemory          = operandTypes{operandTypeNone, operandTypeMemory}
-	operandTypesNoneToBranch          = operandTypes{operandTypeNone, operandTypeBranch}
-	operandTypesRegisterToNone        = operandTypes{operandTypeRegister, operandTypeNone}
-	operandTypesRegisterToRegister    = operandTypes{operandTypeRegister, operandTypeRegister}
-	operandTypesRegisterToMemory      = operandTypes{operandTypeRegister, operandTypeMemory}
-	operandTypesRegisterToConst       = operandTypes{operandTypeRegister, operandTypeConst}
-	operandTypesMemoryToRegister      = operandTypes{operandTypeMemory, operandTypeRegister}
-	operandTypesMemoryToConst         = operandTypes{operandTypeMemory, operandTypeConst}
-	operandTypesConstToRegister       = operandTypes{operandTypeConst, operandTypeRegister}
-	operandTypesConstToMemory         = operandTypes{operandTypeConst, operandTypeMemory}
-	operandTypesStaticConstToRegister = operandTypes{operandTypeStaticConst, operandTypeRegister}
-	operandTypesRegisterToStaticConst = operandTypes{operandTypeRegister, operandTypeStaticConst}
-)
-
-// String implements fmt.Stringer
-func (o operandTypes) String() string {
-	return fmt.Sprintf("from:%s,to:%s", o.src, o.dst)
-}
-
 type (
 	// AssemblerImpl implements Assembler.
 	AssemblerImpl struct {
@@ -370,12 +368,12 @@ func (a *AssemblerImpl) encodeNode(n *nodeImpl) (err error) {
 		err = a.encodeRegisterToConst(n)
 	case operandTypesMemoryToRegister:
 		err = a.encodeMemoryToRegister(n)
+	case operandTypesMemoryToConst:
+		err = a.encodeMemoryToConst(n)
 	case operandTypesConstToRegister:
 		err = a.encodeConstToRegister(n)
 	case operandTypesConstToMemory:
 		err = a.encodeConstToMemory(n)
-	case operandTypesMemoryToConst:
-		err = a.encodeMemoryToConst(n)
 	case operandTypesStaticConstToRegister:
 		err = a.encodeStaticConstToRegister(n)
 	case operandTypesRegisterToStaticConst:
@@ -596,8 +594,7 @@ func (a *AssemblerImpl) fusedInstructionLength(n *nodeImpl) (ret int32, err erro
 	isTest := inst == TESTL || inst == TESTQ
 	isCmp := inst == CMPQ || inst == CMPL
 	isTestCmp := isTest || isCmp
-	if isTestCmp && ((n.types.src == operandTypeMemory && n.types.dst == operandTypeConst) ||
-		(n.types.src == operandTypeConst && n.types.dst == operandTypeMemory)) {
+	if isTestCmp && (n.types == operandTypesMemoryToConst || n.types == operandTypesConstToMemory) {
 		// The manual says: "CMP and TEST can not be fused when comparing MEM-IMM".
 		return
 	}
@@ -1014,7 +1011,7 @@ func (a *AssemblerImpl) encodeNoneToRegister(n *nodeImpl) (err error) {
 }
 
 func (a *AssemblerImpl) encodeNoneToMemory(n *nodeImpl) (err error) {
-	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation()
+	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation(true)
 	if err != nil {
 		return err
 	}
@@ -1699,7 +1696,7 @@ func (a *AssemblerImpl) encodeRegisterToRegister(n *nodeImpl) (err error) {
 }
 
 func (a *AssemblerImpl) encodeRegisterToMemory(n *nodeImpl) (err error) {
-	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation()
+	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation(true)
 	if err != nil {
 		return err
 	}
@@ -1948,7 +1945,7 @@ func (a *AssemblerImpl) encodeMemoryToRegister(n *nodeImpl) (err error) {
 		return a.encodeReadInstructionAddress(n)
 	}
 
-	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation()
+	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation(false)
 	if err != nil {
 		return err
 	}
@@ -2382,7 +2379,7 @@ func (a *AssemblerImpl) encodeMemoryToConst(n *nodeImpl) (err error) {
 		return fmt.Errorf("too large target const %d for %s", n.dstConst, InstructionName(n.instruction))
 	}
 
-	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation()
+	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation(false)
 	if err != nil {
 		return err
 	}
@@ -2425,7 +2422,7 @@ func (a *AssemblerImpl) encodeMemoryToConst(n *nodeImpl) (err error) {
 }
 
 func (a *AssemblerImpl) encodeConstToMemory(n *nodeImpl) (err error) {
-	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation()
+	rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation(true)
 	if err != nil {
 		return err
 	}
@@ -2497,17 +2494,14 @@ func (a *AssemblerImpl) writeConst(v int64, length byte) {
 	}
 }
 
-func (n *nodeImpl) getMemoryLocation() (p rexPrefix, modRM byte, sbi byte, sbiExist bool, displacementWidth byte, err error) {
+func (n *nodeImpl) getMemoryLocation(dstMem bool) (p rexPrefix, modRM byte, sbi byte, sbiExist bool, displacementWidth byte, err error) {
 	var baseReg, indexReg asm.Register
 	var offset asm.ConstantValue
 	var scale byte
-	if n.types.dst == operandTypeMemory {
+	if dstMem {
 		baseReg, offset, indexReg, scale = n.dstReg, n.dstConst, n.dstMemIndex, n.dstMemScale
-	} else if n.types.src == operandTypeMemory {
-		baseReg, offset, indexReg, scale = n.srcReg, n.srcConst, n.srcMemIndex, n.srcMemScale
 	} else {
-		err = fmt.Errorf("memory location is not supported for %s", n.types)
-		return
+		baseReg, offset, indexReg, scale = n.srcReg, n.srcConst, n.srcMemIndex, n.srcMemScale
 	}
 
 	if !fitIn32bit(offset) {


Test patch:
diff --git a/internal/asm/amd64/impl_1_test.go b/internal/asm/amd64/impl_1_test.go
index 9c8a4f31..3f065d14 100644
--- a/internal/asm/amd64/impl_1_test.go
+++ b/internal/asm/amd64/impl_1_test.go
@@ -285,8 +285,7 @@ func TestAssemblerImpl_newNode(t *testing.T) {
 	a := NewAssembler()
 	actual := a.newNode(ADDL, operandTypesConstToMemory)
 	require.Equal(t, ADDL, actual.instruction)
-	require.Equal(t, operandTypeConst, actual.types.src)
-	require.Equal(t, operandTypeMemory, actual.types.dst)
+	require.Equal(t, operandTypesConstToMemory, actual.types)
 	require.Equal(t, actual, a.root)
 	require.Equal(t, actual, a.current)
 }
@@ -297,7 +296,7 @@ func TestAssemblerImpl_encodeNode(t *testing.T) {
 		instruction: ADDPD,
 		types:       operandTypesRegisterToMemory,
 	})
-	require.EqualError(t, err, "ADDPD is unsupported for from:register,to:memory type: ADDPD nil, [nil + 0x0]")
+	require.EqualError(t, err, "ADDPD is unsupported for RegisterToMemory type: ADDPD nil, [nil + 0x0]")
 }
 
 func TestAssemblerImpl_padNOP(t *testing.T) {
@@ -343,8 +342,7 @@ func TestAssemblerImpl_CompileStandAlone(t *testing.T) {
 	a.CompileStandAlone(RET)
 	actualNode := a.current
 	require.Equal(t, RET, actualNode.instruction)
-	require.Equal(t, operandTypeNone, actualNode.types.src)
-	require.Equal(t, operandTypeNone, actualNode.types.dst)
+	require.Equal(t, operandTypesNoneToNone, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileConstToRegister(t *testing.T) {
@@ -354,8 +352,7 @@ func TestAssemblerImpl_CompileConstToRegister(t *testing.T) {
 	require.Equal(t, MOVQ, actualNode.instruction)
 	require.Equal(t, int64(1000), actualNode.srcConst)
 	require.Equal(t, RegAX, actualNode.dstReg)
-	require.Equal(t, operandTypeConst, actualNode.types.src)
-	require.Equal(t, operandTypeRegister, actualNode.types.dst)
+	require.Equal(t, operandTypesConstToRegister, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileRegisterToRegister(t *testing.T) {
@@ -365,8 +362,7 @@ func TestAssemblerImpl_CompileRegisterToRegister(t *testing.T) {
 	require.Equal(t, MOVQ, actualNode.instruction)
 	require.Equal(t, RegBX, actualNode.srcReg)
 	require.Equal(t, RegAX, actualNode.dstReg)
-	require.Equal(t, operandTypeRegister, actualNode.types.src)
-	require.Equal(t, operandTypeRegister, actualNode.types.dst)
+	require.Equal(t, operandTypesRegisterToRegister, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileMemoryToRegister(t *testing.T) {
@@ -377,8 +373,7 @@ func TestAssemblerImpl_CompileMemoryToRegister(t *testing.T) {
 	require.Equal(t, RegBX, actualNode.srcReg)
 	require.Equal(t, int64(100), actualNode.srcConst)
 	require.Equal(t, RegAX, actualNode.dstReg)
-	require.Equal(t, operandTypeMemory, actualNode.types.src)
-	require.Equal(t, operandTypeRegister, actualNode.types.dst)
+	require.Equal(t, operandTypesMemoryToRegister, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileRegisterToMemory(t *testing.T) {
@@ -389,8 +384,7 @@ func TestAssemblerImpl_CompileRegisterToMemory(t *testing.T) {
 	require.Equal(t, RegBX, actualNode.srcReg)
 	require.Equal(t, RegAX, actualNode.dstReg)
 	require.Equal(t, int64(100), actualNode.dstConst)
-	require.Equal(t, operandTypeRegister, actualNode.types.src)
-	require.Equal(t, operandTypeMemory, actualNode.types.dst)
+	require.Equal(t, operandTypesRegisterToMemory, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileJump(t *testing.T) {
@@ -398,8 +392,7 @@ func TestAssemblerImpl_CompileJump(t *testing.T) {
 	a.CompileJump(JMP)
 	actualNode := a.current
 	require.Equal(t, JMP, actualNode.instruction)
-	require.Equal(t, operandTypeNone, actualNode.types.src)
-	require.Equal(t, operandTypeBranch, actualNode.types.dst)
+	require.Equal(t, operandTypesNoneToBranch, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileJumpToRegister(t *testing.T) {
@@ -408,8 +401,7 @@ func TestAssemblerImpl_CompileJumpToRegister(t *testing.T) {
 	actualNode := a.current
 	require.Equal(t, JNE, actualNode.instruction)
 	require.Equal(t, RegAX, actualNode.dstReg)
-	require.Equal(t, operandTypeNone, actualNode.types.src)
-	require.Equal(t, operandTypeRegister, actualNode.types.dst)
+	require.Equal(t, operandTypesNoneToRegister, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileJumpToMemory(t *testing.T) {
@@ -419,8 +411,7 @@ func TestAssemblerImpl_CompileJumpToMemory(t *testing.T) {
 	require.Equal(t, JNE, actualNode.instruction)
 	require.Equal(t, RegAX, actualNode.dstReg)
 	require.Equal(t, int64(100), actualNode.dstConst)
-	require.Equal(t, operandTypeNone, actualNode.types.src)
-	require.Equal(t, operandTypeMemory, actualNode.types.dst)
+	require.Equal(t, operandTypesNoneToMemory, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileReadInstructionAddress(t *testing.T) {
@@ -429,8 +420,7 @@ func TestAssemblerImpl_CompileReadInstructionAddress(t *testing.T) {
 	actualNode := a.current
 	require.Equal(t, LEAQ, actualNode.instruction)
 	require.Equal(t, RegR10, actualNode.dstReg)
-	require.Equal(t, operandTypeMemory, actualNode.types.src)
-	require.Equal(t, operandTypeRegister, actualNode.types.dst)
+	require.Equal(t, operandTypesMemoryToRegister, actualNode.types)
 	require.Equal(t, RET, actualNode.readInstructionAddressBeforeTargetInstruction)
 }
 
@@ -442,8 +432,7 @@ func TestAssemblerImpl_CompileRegisterToRegisterWithArg(t *testing.T) {
 	require.Equal(t, RegBX, actualNode.srcReg)
 	require.Equal(t, RegAX, actualNode.dstReg)
 	require.Equal(t, byte(123), actualNode.arg)
-	require.Equal(t, operandTypeRegister, actualNode.types.src)
-	require.Equal(t, operandTypeRegister, actualNode.types.dst)
+	require.Equal(t, operandTypesRegisterToRegister, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileMemoryWithIndexToRegister(t *testing.T) {
@@ -456,8 +445,7 @@ func TestAssemblerImpl_CompileMemoryWithIndexToRegister(t *testing.T) {
 	require.Equal(t, RegR10, actualNode.srcMemIndex)
 	require.Equal(t, byte(8), actualNode.srcMemScale)
 	require.Equal(t, RegAX, actualNode.dstReg)
-	require.Equal(t, operandTypeMemory, actualNode.types.src)
-	require.Equal(t, operandTypeRegister, actualNode.types.dst)
+	require.Equal(t, operandTypesMemoryToRegister, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileRegisterToConst(t *testing.T) {
@@ -466,8 +454,7 @@ func TestAssemblerImpl_CompileRegisterToConst(t *testing.T) {
 	actualNode := a.current
 	require.Equal(t, RegBX, actualNode.srcReg)
 	require.Equal(t, int64(123), actualNode.dstConst)
-	require.Equal(t, operandTypeRegister, actualNode.types.src)
-	require.Equal(t, operandTypeConst, actualNode.types.dst)
+	require.Equal(t, operandTypesRegisterToConst, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileRegisterToNone(t *testing.T) {
@@ -475,8 +462,7 @@ func TestAssemblerImpl_CompileRegisterToNone(t *testing.T) {
 	a.CompileRegisterToNone(MOVQ, RegBX)
 	actualNode := a.current
 	require.Equal(t, RegBX, actualNode.srcReg)
-	require.Equal(t, operandTypeRegister, actualNode.types.src)
-	require.Equal(t, operandTypeNone, actualNode.types.dst)
+	require.Equal(t, operandTypesRegisterToNone, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileNoneToRegister(t *testing.T) {
@@ -484,8 +470,7 @@ func TestAssemblerImpl_CompileNoneToRegister(t *testing.T) {
 	a.CompileNoneToRegister(MOVQ, RegBX)
 	actualNode := a.current
 	require.Equal(t, RegBX, actualNode.dstReg)
-	require.Equal(t, operandTypeNone, actualNode.types.src)
-	require.Equal(t, operandTypeRegister, actualNode.types.dst)
+	require.Equal(t, operandTypesNoneToRegister, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileNoneToMemory(t *testing.T) {
@@ -494,8 +479,7 @@ func TestAssemblerImpl_CompileNoneToMemory(t *testing.T) {
 	actualNode := a.current
 	require.Equal(t, RegBX, actualNode.dstReg)
 	require.Equal(t, int64(1234), actualNode.dstConst)
-	require.Equal(t, operandTypeNone, actualNode.types.src)
-	require.Equal(t, operandTypeMemory, actualNode.types.dst)
+	require.Equal(t, operandTypesNoneToMemory, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileConstToMemory(t *testing.T) {
@@ -505,8 +489,7 @@ func TestAssemblerImpl_CompileConstToMemory(t *testing.T) {
 	require.Equal(t, RegBX, actualNode.dstReg)
 	require.Equal(t, int64(-9999), actualNode.srcConst)
 	require.Equal(t, int64(1234), actualNode.dstConst)
-	require.Equal(t, operandTypeConst, actualNode.types.src)
-	require.Equal(t, operandTypeMemory, actualNode.types.dst)
+	require.Equal(t, operandTypesConstToMemory, actualNode.types)
 }
 
 func TestAssemblerImpl_CompileMemoryToConst(t *testing.T) {
@@ -516,8 +499,7 @@ func TestAssemblerImpl_CompileMemoryToConst(t *testing.T) {
 	require.Equal(t, RegBX, actualNode.srcReg)
 	require.Equal(t, int64(1234), actualNode.srcConst)
 	require.Equal(t, int64(-9999), actualNode.dstConst)
-	require.Equal(t, operandTypeMemory, actualNode.types.src)
-	require.Equal(t, operandTypeConst, actualNode.types.dst)
+	require.Equal(t, operandTypesMemoryToConst, actualNode.types)
 }
 
 func TestAssemblerImpl_encodeNoneToNone(t *testing.T) {
diff --git a/internal/asm/amd64/impl_2_test.go b/internal/asm/amd64/impl_2_test.go
index 7cb65720..4c81fdde 100644
--- a/internal/asm/amd64/impl_2_test.go
+++ b/internal/asm/amd64/impl_2_test.go
@@ -23,7 +23,7 @@ func TestAssemblerImpl_EncodeNoneToRegister(t *testing.T) {
 			}{
 				{
 					n:      &nodeImpl{instruction: ADDL, types: operandTypesNoneToRegister, dstReg: RegAX},
-					expErr: "ADDL is unsupported for from:none,to:register type",
+					expErr: "ADDL is unsupported for NoneToRegister type",
 				},
 			}
 
@@ -236,7 +236,7 @@ func TestAssemblerImpl_EncodeNoneToMemory(t *testing.T) {
 		}{
 			{
 				n:      &nodeImpl{instruction: ADDL, types: operandTypesNoneToMemory, dstReg: RegAX},
-				expErr: "ADDL is unsupported for from:none,to:memory type",
+				expErr: "ADDL is unsupported for NoneToMemory type",
 			},
 		}
 
@@ -478,7 +478,7 @@ func TestAssemblerImpl_EncodeRegisterToNone(t *testing.T) {
 		}{
 			{
 				n:      &nodeImpl{instruction: ADDL, types: operandTypesRegisterToNone, srcReg: RegAX},
-				expErr: "ADDL is unsupported for from:register,to:none type",
+				expErr: "ADDL is unsupported for RegisterToNone type",
 			},
 		}
 
@@ -582,7 +582,7 @@ func TestAssemblerImpl_EncodeRegisterToRegister(t *testing.T) {
 		}{
 			{
 				n:      &nodeImpl{instruction: JMP, types: operandTypesRegisterToRegister, srcReg: RegAX, dstReg: RegAX},
-				expErr: "JMP is unsupported for from:register,to:register type",
+				expErr: "JMP is unsupported for RegisterToRegister type",
 			},
 		}
 
diff --git a/internal/asm/amd64/impl_3_test.go b/internal/asm/amd64/impl_3_test.go
index 74f2c7ac..558714f4 100644
--- a/internal/asm/amd64/impl_3_test.go
+++ b/internal/asm/amd64/impl_3_test.go
@@ -18,7 +18,7 @@ func TestAssemblerImpl_EncodeRegisterToMemory(t *testing.T) {
 					types:       operandTypesRegisterToMemory,
 					srcReg:      RegAX, dstReg: RegAX,
 				},
-				expErr: "JMP is unsupported for from:register,to:memory type",
+				expErr: "JMP is unsupported for RegisterToMemory type",
 			},
 			{
 				n: &nodeImpl{
diff --git a/internal/asm/amd64/impl_4_test.go b/internal/asm/amd64/impl_4_test.go
index 16e0938f..a5542436 100644
--- a/internal/asm/amd64/impl_4_test.go
+++ b/internal/asm/amd64/impl_4_test.go
@@ -16,7 +16,7 @@ func TestAssemblerImpl_encodeConstToRegister(t *testing.T) {
 		}{
 			{
 				n:      &nodeImpl{instruction: RET, types: operandTypesConstToRegister, dstReg: RegAX},
-				expErr: "RET is unsupported for from:const,to:register type",
+				expErr: "RET is unsupported for ConstToRegister type",
 			},
 			{
 				n:      &nodeImpl{instruction: PSLLD, types: operandTypesConstToRegister},
@@ -350,7 +350,7 @@ func TestAssemblerImpl_encodeRegisterToConst(t *testing.T) {
 		}{
 			{
 				n:      &nodeImpl{instruction: ADDL, types: operandTypesRegisterToConst, srcReg: RegAX},
-				expErr: "ADDL is unsupported for from:register,to:const type",
+				expErr: "ADDL is unsupported for RegisterToConst type",
 			},
 		}
 
diff --git a/internal/asm/amd64/impl_5_test.go b/internal/asm/amd64/impl_5_test.go
index 199a21a2..41cdfa96 100644
--- a/internal/asm/amd64/impl_5_test.go
+++ b/internal/asm/amd64/impl_5_test.go
@@ -17,7 +17,7 @@ func TestAssemblerImpl_EncodeConstToMemory(t *testing.T) {
 		}{
 			{
 				n:      &nodeImpl{instruction: ADDL, types: operandTypesConstToMemory, dstReg: RegAX},
-				expErr: "ADDL is unsupported for from:const,to:memory type",
+				expErr: "ADDL is unsupported for ConstToMemory type",
 			},
 			{
 				n: &nodeImpl{
@@ -665,7 +665,7 @@ func TestAssemblerImpl_EncodeMemoryToConst(t *testing.T) {
 		}{
 			{
 				n:      &nodeImpl{instruction: ADDL, types: operandTypesMemoryToConst, dstReg: RegAX},
-				expErr: "ADDL is unsupported for from:memory,to:const type",
+				expErr: "ADDL is unsupported for MemoryToConst type",
 			},
 		}
 
diff --git a/internal/asm/amd64/impl_memorylocation_test.go b/internal/asm/amd64/impl_memorylocation_test.go
index f2397996..d7acd3ef 100644
--- a/internal/asm/amd64/impl_memorylocation_test.go
+++ b/internal/asm/amd64/impl_memorylocation_test.go
@@ -14,33 +14,33 @@ func TestNodeImpl_GetMemoryLocation_errors(t *testing.T) {
 		expErr string
 	}{
 		{
-			n:      &nodeImpl{instruction: ADDL, types: operandTypesMemoryToRegister, srcConst: math.MaxInt64, srcReg: RegAX, dstReg: RegR10},
+			n:      &nodeImpl{instruction: ADDL, srcConst: math.MaxInt64, srcReg: RegAX, dstReg: RegR10},
 			expErr: "offset does not fit in 32-bit integer",
 		},
 		{
 			n: &nodeImpl{
-				instruction: ADDL, types: operandTypesMemoryToRegister,
-				srcConst: 10, srcReg: asm.NilRegister, srcMemIndex: RegR12, srcMemScale: 1, dstReg: RegR10,
+				instruction: ADDL,
+				srcConst:    10, srcReg: asm.NilRegister, srcMemIndex: RegR12, srcMemScale: 1, dstReg: RegR10,
 			},
 			expErr: "addressing without base register but with index is not implemented",
 		},
 		{
 			n: &nodeImpl{
-				instruction: ADDL, types: operandTypesMemoryToRegister,
-				srcConst: 10, srcReg: RegAX, srcMemIndex: RegSP, srcMemScale: 1, dstReg: RegR10,
+				instruction: ADDL,
+				srcConst:    10, srcReg: RegAX, srcMemIndex: RegSP, srcMemScale: 1, dstReg: RegR10,
 			},
 			expErr: "SP cannot be used for SIB index",
 		},
 		{
 			n: &nodeImpl{
-				instruction: ADDL, types: operandTypesMemoryToRegister,
-				srcConst: 10, srcReg: RegAX, srcMemIndex: RegR9, srcMemScale: 3, dstReg: RegR10,
+				instruction: ADDL,
+				srcConst:    10, srcReg: RegAX, srcMemIndex: RegR9, srcMemScale: 3, dstReg: RegR10,
 			},
 			expErr: "scale in SIB must be one of 1, 2, 4, 8 but got 3",
 		},
 	}
 	for _, tt := range tests {
-		_, _, _, _, _, err := tt.n.getMemoryLocation()
+		_, _, _, _, _, err := tt.n.getMemoryLocation(false)
 		require.EqualError(t, err, tt.expErr, tt.expErr)
 	}
 }
@@ -58,10 +58,9 @@ func TestNodeImpl_GetMemoryLocation_without_base(t *testing.T) {
 	}
 	for _, tc := range tests {
 		n := &nodeImpl{
-			types:  operandTypesMemoryToRegister,
 			srcReg: asm.NilRegister, srcConst: tc.offset,
 		}
-		rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation()
+		rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation(false)
 		require.NoError(t, err)
 		require.Equal(t, rexPrefixNone, rexPrefix)
 		require.Equal(t, tc.modRM, modRM)
@@ -1685,10 +1684,9 @@ func TestNodeImpl_GetMemoryLocation_with_base(t *testing.T) {
 	}
 	for _, tc := range tests {
 		n := &nodeImpl{
-			types:  operandTypesMemoryToRegister,
 			srcReg: tc.baseReg, srcConst: tc.offset, srcMemIndex: tc.indexReg, srcMemScale: tc.scale,
 		}
-		rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation()
+		rexPrefix, modRM, sbi, sbiExist, displacementWidth, err := n.getMemoryLocation(false)
 		require.NoError(t, err, tc.name)
 		require.Equal(t, tc.expRex, rexPrefix, tc.name)
 		require.Equal(t, tc.expModRM, modRM, tc.name)
diff --git a/internal/asm/amd64/impl_staticconst_test.go b/internal/asm/amd64/impl_staticconst_test.go
index 6c6f88d0..8e50801c 100644
--- a/internal/asm/amd64/impl_staticconst_test.go
+++ b/internal/asm/amd64/impl_staticconst_test.go
@@ -20,8 +20,7 @@ func TestAssemblerImpl_CompileStaticConstToRegister(t *testing.T) {
 		require.NoError(t, err)
 		actualNode := a.current
 		require.Equal(t, MOVDQU, actualNode.instruction)
-		require.Equal(t, operandTypeStaticConst, actualNode.types.src)
-		require.Equal(t, operandTypeRegister, actualNode.types.dst)
+		require.Equal(t, operandTypesStaticConstToRegister, actualNode.types)
 		require.Equal(t, cons, actualNode.staticConst)
 	})
 }
@@ -38,8 +37,7 @@ func TestAssemblerImpl_CompileRegisterToStaticConst(t *testing.T) {
 		require.NoError(t, err)
 		actualNode := a.current
 		require.Equal(t, MOVDQU, actualNode.instruction)
-		require.Equal(t, operandTypeRegister, actualNode.types.src)
-		require.Equal(t, operandTypeStaticConst, actualNode.types.dst)
+		require.Equal(t, operandTypesRegisterToStaticConst, actualNode.types)
 		require.Equal(t, cons, actualNode.staticConst)
 	})
 }