asm(amd64): ROL and ROR on Register To Memory type. (#423)

Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit is contained in:
Takeshi Yoneda
2022-03-31 15:36:38 +09:00
committed by GitHub
parent be3aed46be
commit a351daa858
3 changed files with 126 additions and 90 deletions

View File

@@ -1299,6 +1299,26 @@ func (a *AssemblerImpl) EncodeRegisterToMemory(n *NodeImpl) (err error) {
modRM |= 0b00_101_000
opcode = []byte{0xd3}
isShiftInstruction = true
case ROLL:
// https://www.felixcloutier.com/x86/rcl:rcr:rol:ror
opcode = []byte{0xd3}
isShiftInstruction = true
case ROLQ:
// https://www.felixcloutier.com/x86/rcl:rcr:rol:ror
RexPrefix |= RexPrefixW
opcode = []byte{0xd3}
isShiftInstruction = true
case RORL:
// https://www.felixcloutier.com/x86/rcl:rcr:rol:ror
modRM |= 0b00_001_000
opcode = []byte{0xd3}
isShiftInstruction = true
case RORQ:
// https://www.felixcloutier.com/x86/rcl:rcr:rol:ror
RexPrefix |= RexPrefixW
opcode = []byte{0xd3}
modRM |= 0b00_001_000
isShiftInstruction = true
default:
return errorEncodingUnsupported(n)
}

View File

@@ -1036,7 +1036,10 @@ func TestAssemblerImpl_EncodeRegisterToMemory(t *testing.T) {
t.Run("shift", func(t *testing.T) {
regs := []asm.Register{amd64.REG_AX, amd64.REG_R8}
scales := []byte{1, 4}
for _, instruction := range []asm.Instruction{amd64.SARL, amd64.SARQ, amd64.SHLL, amd64.SHLQ, amd64.SHRL, amd64.SHRQ} {
for _, instruction := range []asm.Instruction{
amd64.SARL, amd64.SARQ, amd64.SHLL, amd64.SHLQ, amd64.SHRL, amd64.SHRQ,
amd64.ROLL, amd64.ROLQ, amd64.RORL, amd64.RORQ,
} {
for _, DstReg := range regs {
DstReg := DstReg
for _, offset := range []int64{

View File

@@ -279,21 +279,35 @@ func TestCompiler_compile_And_Or_Xor_Shl_Rotl_Rotr(t *testing.T) {
{1 << 63, 1}, {1, 1 << 63}, {1 << 63, 1 << 63},
} {
x1, x2 := values[0], values[1]
t.Run(fmt.Sprintf("x1=0x%x,x2=0x%x", x1, x2), func(t *testing.T) {
for _, x1OnRegister := range []bool{
true, false,
} {
x1OnRegister := x1OnRegister
t.Run(fmt.Sprintf("x1=0x%x(on_register=%v),x2=0x%x", x1, x1OnRegister, x2), func(t *testing.T) {
env := newJITEnvironment()
compiler := env.requireNewCompiler(t, newCompiler, nil)
err := compiler.compilePreamble()
require.NoError(t, err)
// Emit consts operands.
for _, v := range []uint64{x1, x2} {
var x1Location *valueLocation
switch unsignedInt {
case wazeroir.UnsignedInt32:
err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(v)})
case wazeroir.UnsignedInt64:
err = compiler.compileConstI64(&wazeroir.OperationConstI64{Value: v})
}
err = compiler.compileConstI32(&wazeroir.OperationConstI32{Value: uint32(x1)})
require.NoError(t, err)
x1Location = compiler.valueLocationStack().peek()
err = compiler.compileConstI64(&wazeroir.OperationConstI64{Value: x2})
require.NoError(t, err)
case wazeroir.UnsignedInt64:
err = compiler.compileConstI64(&wazeroir.OperationConstI64{Value: x1})
require.NoError(t, err)
x1Location = compiler.valueLocationStack().peek()
err = compiler.compileConstI64(&wazeroir.OperationConstI64{Value: x2})
require.NoError(t, err)
}
if !x1OnRegister {
compiler.compileReleaseRegisterToStack(x1Location)
}
// At this point, two values exist.
@@ -319,8 +333,6 @@ func TestCompiler_compile_And_Or_Xor_Shl_Rotl_Rotr(t *testing.T) {
// We consumed two values, but push the result back.
require.Equal(t, uint64(1), compiler.valueLocationStack().sp)
resultLocation := compiler.valueLocationStack().peek()
// Plus the result must be located on a register.
require.True(t, resultLocation.onRegister())
// Also, the result must have an appropriate register type.
require.Equal(t, generalPurposeRegisterTypeInt, resultLocation.regType)
@@ -381,6 +393,7 @@ func TestCompiler_compile_And_Or_Xor_Shl_Rotl_Rotr(t *testing.T) {
}
})
}
}
})
}
})