summaryrefslogtreecommitdiffstats
path: root/src/cmd/internal/obj/x86/asm_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/internal/obj/x86/asm_test.go')
-rw-r--r--src/cmd/internal/obj/x86/asm_test.go291
1 files changed, 291 insertions, 0 deletions
diff --git a/src/cmd/internal/obj/x86/asm_test.go b/src/cmd/internal/obj/x86/asm_test.go
new file mode 100644
index 0000000..36c8fce
--- /dev/null
+++ b/src/cmd/internal/obj/x86/asm_test.go
@@ -0,0 +1,291 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x86
+
+import (
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "testing"
+)
+
+type oclassTest struct {
+ arg *obj.Addr
+ want int // Expected oclass return value for a given arg
+}
+
+// Filled inside init, because it's easier to do with helper functions.
+var (
+ oclassTestsAMD64 []*oclassTest
+ oclassTests386 []*oclassTest
+)
+
+func init() {
+ // Required for tests that access any of
+ // opindex/ycover/reg/regrex global tables.
+ var ctxt obj.Link
+ instinit(&ctxt)
+
+ regAddr := func(reg int16) *obj.Addr {
+ return &obj.Addr{Type: obj.TYPE_REG, Reg: reg}
+ }
+ immAddr := func(v int64) *obj.Addr {
+ return &obj.Addr{Type: obj.TYPE_CONST, Offset: v}
+ }
+ regListAddr := func(regFrom, regTo int16) *obj.Addr {
+ return &obj.Addr{Type: obj.TYPE_REGLIST, Offset: EncodeRegisterRange(regFrom, regTo)}
+ }
+ memAddr := func(base, index int16) *obj.Addr {
+ return &obj.Addr{Type: obj.TYPE_MEM, Reg: base, Index: index}
+ }
+
+ // TODO(quasilyte): oclass doesn't return Yxxx for X/Y regs with
+ // ID higher than 7. We don't encode such instructions, but this
+ // behavior seems inconsistent. It should probably either
+ // never check for arch or do it in all cases.
+
+ oclassTestsCommon := []*oclassTest{
+ {&obj.Addr{Type: obj.TYPE_NONE}, Ynone},
+ {&obj.Addr{Type: obj.TYPE_BRANCH}, Ybr},
+ {&obj.Addr{Type: obj.TYPE_TEXTSIZE}, Ytextsize},
+
+ {&obj.Addr{Type: obj.TYPE_INDIR, Name: obj.NAME_EXTERN}, Yindir},
+ {&obj.Addr{Type: obj.TYPE_INDIR, Name: obj.NAME_GOTREF}, Yindir},
+
+ {&obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_AUTO}, Yiauto},
+ {&obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_PARAM}, Yiauto},
+ {&obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN}, Yiauto},
+ {&obj.Addr{Type: obj.TYPE_ADDR, Sym: &obj.LSym{Name: "runtime.duff"}}, Yi32},
+ {&obj.Addr{Type: obj.TYPE_ADDR, Offset: 4}, Yu7},
+ {&obj.Addr{Type: obj.TYPE_ADDR, Offset: 255}, Yu8},
+
+ {immAddr(0), Yi0},
+ {immAddr(1), Yi1},
+ {immAddr(2), Yu2},
+ {immAddr(3), Yu2},
+ {immAddr(4), Yu7},
+ {immAddr(86), Yu7},
+ {immAddr(127), Yu7},
+ {immAddr(128), Yu8},
+ {immAddr(200), Yu8},
+ {immAddr(255), Yu8},
+ {immAddr(-1), Yi8},
+ {immAddr(-100), Yi8},
+ {immAddr(-128), Yi8},
+
+ {regAddr(REG_AL), Yal},
+ {regAddr(REG_AX), Yax},
+ {regAddr(REG_DL), Yrb},
+ {regAddr(REG_DH), Yrb},
+ {regAddr(REG_BH), Yrb},
+ {regAddr(REG_CL), Ycl},
+ {regAddr(REG_CX), Ycx},
+ {regAddr(REG_DX), Yrx},
+ {regAddr(REG_BX), Yrx},
+ {regAddr(REG_F0), Yf0},
+ {regAddr(REG_F3), Yrf},
+ {regAddr(REG_F7), Yrf},
+ {regAddr(REG_M0), Ymr},
+ {regAddr(REG_M3), Ymr},
+ {regAddr(REG_M7), Ymr},
+ {regAddr(REG_X0), Yxr0},
+ {regAddr(REG_X6), Yxr},
+ {regAddr(REG_X13), Yxr},
+ {regAddr(REG_X20), YxrEvex},
+ {regAddr(REG_X31), YxrEvex},
+ {regAddr(REG_Y0), Yyr},
+ {regAddr(REG_Y6), Yyr},
+ {regAddr(REG_Y13), Yyr},
+ {regAddr(REG_Y20), YyrEvex},
+ {regAddr(REG_Y31), YyrEvex},
+ {regAddr(REG_Z0), Yzr},
+ {regAddr(REG_Z6), Yzr},
+ {regAddr(REG_K0), Yk0},
+ {regAddr(REG_K5), Yknot0},
+ {regAddr(REG_K7), Yknot0},
+ {regAddr(REG_CS), Ycs},
+ {regAddr(REG_SS), Yss},
+ {regAddr(REG_DS), Yds},
+ {regAddr(REG_ES), Yes},
+ {regAddr(REG_FS), Yfs},
+ {regAddr(REG_GS), Ygs},
+ {regAddr(REG_TLS), Ytls},
+ {regAddr(REG_GDTR), Ygdtr},
+ {regAddr(REG_IDTR), Yidtr},
+ {regAddr(REG_LDTR), Yldtr},
+ {regAddr(REG_MSW), Ymsw},
+ {regAddr(REG_TASK), Ytask},
+ {regAddr(REG_CR0), Ycr0},
+ {regAddr(REG_CR5), Ycr5},
+ {regAddr(REG_CR8), Ycr8},
+ {regAddr(REG_DR0), Ydr0},
+ {regAddr(REG_DR5), Ydr5},
+ {regAddr(REG_DR7), Ydr7},
+ {regAddr(REG_TR0), Ytr0},
+ {regAddr(REG_TR5), Ytr5},
+ {regAddr(REG_TR7), Ytr7},
+
+ {regListAddr(REG_X0, REG_X3), YxrEvexMulti4},
+ {regListAddr(REG_X4, REG_X7), YxrEvexMulti4},
+ {regListAddr(REG_Y0, REG_Y3), YyrEvexMulti4},
+ {regListAddr(REG_Y4, REG_Y7), YyrEvexMulti4},
+ {regListAddr(REG_Z0, REG_Z3), YzrMulti4},
+ {regListAddr(REG_Z4, REG_Z7), YzrMulti4},
+
+ {memAddr(REG_AL, REG_NONE), Ym},
+ {memAddr(REG_AL, REG_SI), Ym},
+ {memAddr(REG_SI, REG_CX), Ym},
+ {memAddr(REG_DI, REG_X0), Yxvm},
+ {memAddr(REG_DI, REG_X7), Yxvm},
+ {memAddr(REG_DI, REG_Y0), Yyvm},
+ {memAddr(REG_DI, REG_Y7), Yyvm},
+ {memAddr(REG_DI, REG_Z0), Yzvm},
+ {memAddr(REG_DI, REG_Z7), Yzvm},
+ }
+
+ oclassTestsAMD64 = []*oclassTest{
+ {immAddr(-200), Ys32},
+ {immAddr(500), Ys32},
+ {immAddr(0x7FFFFFFF), Ys32},
+ {immAddr(0x7FFFFFFF + 1), Yi32},
+ {immAddr(0xFFFFFFFF), Yi32},
+ {immAddr(0xFFFFFFFF + 1), Yi64},
+
+ {regAddr(REG_BPB), Yrb},
+ {regAddr(REG_SIB), Yrb},
+ {regAddr(REG_DIB), Yrb},
+ {regAddr(REG_R8B), Yrb},
+ {regAddr(REG_R12B), Yrb},
+ {regAddr(REG_R8), Yrl},
+ {regAddr(REG_R13), Yrl},
+ {regAddr(REG_R15), Yrl},
+ {regAddr(REG_SP), Yrl},
+ {regAddr(REG_SI), Yrl},
+ {regAddr(REG_DI), Yrl},
+ {regAddr(REG_Z13), Yzr},
+ {regAddr(REG_Z20), Yzr},
+ {regAddr(REG_Z31), Yzr},
+
+ {regListAddr(REG_X10, REG_X13), YxrEvexMulti4},
+ {regListAddr(REG_X24, REG_X27), YxrEvexMulti4},
+ {regListAddr(REG_Y10, REG_Y13), YyrEvexMulti4},
+ {regListAddr(REG_Y24, REG_Y27), YyrEvexMulti4},
+ {regListAddr(REG_Z10, REG_Z13), YzrMulti4},
+ {regListAddr(REG_Z24, REG_Z27), YzrMulti4},
+
+ {memAddr(REG_DI, REG_X20), YxvmEvex},
+ {memAddr(REG_DI, REG_X27), YxvmEvex},
+ {memAddr(REG_DI, REG_Y20), YyvmEvex},
+ {memAddr(REG_DI, REG_Y27), YyvmEvex},
+ {memAddr(REG_DI, REG_Z20), Yzvm},
+ {memAddr(REG_DI, REG_Z27), Yzvm},
+ }
+
+ oclassTests386 = []*oclassTest{
+ {&obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN, Sym: &obj.LSym{}}, Yi32},
+
+ {immAddr(-200), Yi32},
+
+ {regAddr(REG_SP), Yrl32},
+ {regAddr(REG_SI), Yrl32},
+ {regAddr(REG_DI), Yrl32},
+ }
+
+ // Add tests that are arch-independent for all sets.
+ oclassTestsAMD64 = append(oclassTestsAMD64, oclassTestsCommon...)
+ oclassTests386 = append(oclassTests386, oclassTestsCommon...)
+}
+
+func TestOclass(t *testing.T) {
+ runTest := func(t *testing.T, ctxt *obj.Link, tests []*oclassTest) {
+ var p obj.Prog
+ for _, test := range tests {
+ have := oclass(ctxt, &p, test.arg)
+ if have != test.want {
+ t.Errorf("oclass(%q):\nhave: %d\nwant: %d",
+ obj.Dconv(&p, test.arg), have, test.want)
+ }
+ }
+ }
+
+ // TODO(quasilyte): test edge cases for Hsolaris, etc?
+
+ t.Run("linux/AMD64", func(t *testing.T) {
+ ctxtAMD64 := obj.Linknew(&Linkamd64)
+ ctxtAMD64.Headtype = objabi.Hlinux // See #32028
+ runTest(t, ctxtAMD64, oclassTestsAMD64)
+ })
+
+ t.Run("linux/386", func(t *testing.T) {
+ ctxt386 := obj.Linknew(&Link386)
+ ctxt386.Headtype = objabi.Hlinux // See #32028
+ runTest(t, ctxt386, oclassTests386)
+ })
+}
+
+func TestRegisterListEncDec(t *testing.T) {
+ tests := []struct {
+ printed string
+ reg0 int16
+ reg1 int16
+ }{
+ {"[R10-R13]", REG_R10, REG_R13},
+ {"[X0-AX]", REG_X0, REG_AX},
+
+ {"[X0-X3]", REG_X0, REG_X3},
+ {"[X21-X24]", REG_X21, REG_X24},
+
+ {"[Y0-Y3]", REG_Y0, REG_Y3},
+ {"[Y21-Y24]", REG_Y21, REG_Y24},
+
+ {"[Z0-Z3]", REG_Z0, REG_Z3},
+ {"[Z21-Z24]", REG_Z21, REG_Z24},
+ }
+
+ for _, test := range tests {
+ enc := EncodeRegisterRange(test.reg0, test.reg1)
+ reg0, reg1 := decodeRegisterRange(enc)
+
+ if int16(reg0) != test.reg0 {
+ t.Errorf("%s reg0 mismatch: have %d, want %d",
+ test.printed, reg0, test.reg0)
+ }
+ if int16(reg1) != test.reg1 {
+ t.Errorf("%s reg1 mismatch: have %d, want %d",
+ test.printed, reg1, test.reg1)
+ }
+ wantPrinted := test.printed
+ if rlconv(enc) != wantPrinted {
+ t.Errorf("%s string mismatch: have %s, want %s",
+ test.printed, rlconv(enc), wantPrinted)
+ }
+ }
+}
+
+func TestRegIndex(t *testing.T) {
+ tests := []struct {
+ regFrom int
+ regTo int
+ }{
+ {REG_AL, REG_R15B},
+ {REG_AX, REG_R15},
+ {REG_M0, REG_M7},
+ {REG_K0, REG_K7},
+ {REG_X0, REG_X31},
+ {REG_Y0, REG_Y31},
+ {REG_Z0, REG_Z31},
+ }
+
+ for _, test := range tests {
+ for index, reg := 0, test.regFrom; reg <= test.regTo; index, reg = index+1, reg+1 {
+ have := regIndex(int16(reg))
+ want := index
+ if have != want {
+ regName := rconv(int(reg))
+ t.Errorf("regIndex(%s):\nhave: %d\nwant: %d",
+ regName, have, want)
+ }
+ }
+ }
+}