github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/engine/wazevo/backend/isa/arm64/abi_test.go (about)

     1  package arm64
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/wasilibs/wazerox/internal/engine/wazevo/backend"
     7  	"github.com/wasilibs/wazerox/internal/engine/wazevo/backend/regalloc"
     8  	"github.com/wasilibs/wazerox/internal/engine/wazevo/ssa"
     9  	"github.com/wasilibs/wazerox/internal/testing/require"
    10  )
    11  
    12  func TestAbiImpl_init(t *testing.T) {
    13  	for _, tc := range []struct {
    14  		name string
    15  		sig  *ssa.Signature
    16  		exp  abiImpl
    17  	}{
    18  		{
    19  			name: "empty sig",
    20  			sig:  &ssa.Signature{},
    21  			exp:  abiImpl{},
    22  		},
    23  		{
    24  			name: "small sig",
    25  			sig: &ssa.Signature{
    26  				Params:  []ssa.Type{ssa.TypeI32, ssa.TypeF32, ssa.TypeI32},
    27  				Results: []ssa.Type{ssa.TypeI64, ssa.TypeF64},
    28  			},
    29  			exp: abiImpl{
    30  				m: nil,
    31  				args: []backend.ABIArg{
    32  					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
    33  					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
    34  					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI32},
    35  				},
    36  				rets: []backend.ABIArg{
    37  					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI64},
    38  					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF64},
    39  				},
    40  				argRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg},
    41  				retRealRegs: []regalloc.VReg{x0VReg, v0VReg},
    42  			},
    43  		},
    44  		{
    45  			name: "regs stack mix and match",
    46  			sig: &ssa.Signature{
    47  				Params: []ssa.Type{
    48  					ssa.TypeI32, ssa.TypeF32,
    49  					ssa.TypeI64, ssa.TypeF64,
    50  					ssa.TypeI32, ssa.TypeF32,
    51  					ssa.TypeI64, ssa.TypeF64,
    52  					ssa.TypeI32, ssa.TypeF32,
    53  					ssa.TypeI64, ssa.TypeF64,
    54  					ssa.TypeI32, ssa.TypeF32,
    55  					ssa.TypeI64, ssa.TypeF64,
    56  					ssa.TypeI32, ssa.TypeF32,
    57  					ssa.TypeI64, ssa.TypeF64,
    58  					ssa.TypeI32, ssa.TypeF32,
    59  					ssa.TypeI64, ssa.TypeF64,
    60  					ssa.TypeI32, ssa.TypeF32,
    61  					ssa.TypeI64, ssa.TypeF64,
    62  					ssa.TypeI32, ssa.TypeF32,
    63  					ssa.TypeI64, ssa.TypeF64,
    64  				},
    65  				Results: []ssa.Type{
    66  					ssa.TypeI32, ssa.TypeF32,
    67  					ssa.TypeI64, ssa.TypeF64,
    68  					ssa.TypeI32, ssa.TypeF32,
    69  					ssa.TypeI64, ssa.TypeF64,
    70  					ssa.TypeI32, ssa.TypeF32,
    71  					ssa.TypeI64, ssa.TypeF64,
    72  					ssa.TypeI32, ssa.TypeF32,
    73  					ssa.TypeI64, ssa.TypeF64,
    74  					ssa.TypeI32, ssa.TypeF32,
    75  					ssa.TypeI64, ssa.TypeF64,
    76  					ssa.TypeI32, ssa.TypeF32,
    77  					ssa.TypeI64, ssa.TypeF64,
    78  					ssa.TypeI32, ssa.TypeF32,
    79  					ssa.TypeI64, ssa.TypeF64,
    80  					ssa.TypeI32, ssa.TypeF32,
    81  					ssa.TypeI64, ssa.TypeF64,
    82  				},
    83  			},
    84  			exp: abiImpl{
    85  				argStackSize: 128, retStackSize: 128,
    86  				args: []backend.ABIArg{
    87  					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
    88  					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
    89  					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
    90  					{Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
    91  					{Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
    92  					{Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
    93  					{Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
    94  					{Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
    95  					{Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
    96  					{Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
    97  					{Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
    98  					{Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
    99  					{Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
   100  					{Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
   101  					{Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
   102  					{Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
   103  					{Index: 16, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 0},
   104  					{Index: 17, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 8},
   105  					{Index: 18, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 16},
   106  					{Index: 19, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 24},
   107  					{Index: 20, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 32},
   108  					{Index: 21, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 40},
   109  					{Index: 22, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 48},
   110  					{Index: 23, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 56},
   111  					{Index: 24, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 64},
   112  					{Index: 25, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 72},
   113  					{Index: 26, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 80},
   114  					{Index: 27, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 88},
   115  					{Index: 28, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 96},
   116  					{Index: 29, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 104},
   117  					{Index: 30, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 112},
   118  					{Index: 31, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 120},
   119  				},
   120  				rets: []backend.ABIArg{
   121  					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
   122  					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
   123  					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
   124  					{Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
   125  					{Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
   126  					{Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
   127  					{Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
   128  					{Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
   129  					{Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
   130  					{Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
   131  					{Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
   132  					{Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
   133  					{Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
   134  					{Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
   135  					{Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
   136  					{Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
   137  					{Index: 16, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 0},
   138  					{Index: 17, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 8},
   139  					{Index: 18, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 16},
   140  					{Index: 19, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 24},
   141  					{Index: 20, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 32},
   142  					{Index: 21, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 40},
   143  					{Index: 22, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 48},
   144  					{Index: 23, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 56},
   145  					{Index: 24, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 64},
   146  					{Index: 25, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 72},
   147  					{Index: 26, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 80},
   148  					{Index: 27, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 88},
   149  					{Index: 28, Kind: backend.ABIArgKindStack, Type: ssa.TypeI32, Offset: 96},
   150  					{Index: 29, Kind: backend.ABIArgKindStack, Type: ssa.TypeF32, Offset: 104},
   151  					{Index: 30, Kind: backend.ABIArgKindStack, Type: ssa.TypeI64, Offset: 112},
   152  					{Index: 31, Kind: backend.ABIArgKindStack, Type: ssa.TypeF64, Offset: 120},
   153  				},
   154  				retRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg},
   155  				argRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg},
   156  			},
   157  		},
   158  		{
   159  			name: "all regs",
   160  			sig: &ssa.Signature{
   161  				Params: []ssa.Type{
   162  					ssa.TypeI32, ssa.TypeF32,
   163  					ssa.TypeI64, ssa.TypeF64,
   164  					ssa.TypeI32, ssa.TypeF32,
   165  					ssa.TypeI64, ssa.TypeF64,
   166  					ssa.TypeI32, ssa.TypeF32,
   167  					ssa.TypeI64, ssa.TypeF64,
   168  					ssa.TypeI32, ssa.TypeF32,
   169  					ssa.TypeI64, ssa.TypeF64,
   170  				},
   171  				Results: []ssa.Type{
   172  					ssa.TypeI32, ssa.TypeF32,
   173  					ssa.TypeI64, ssa.TypeF64,
   174  					ssa.TypeI32, ssa.TypeF32,
   175  					ssa.TypeI64, ssa.TypeF64,
   176  					ssa.TypeI32, ssa.TypeF32,
   177  					ssa.TypeI64, ssa.TypeF64,
   178  					ssa.TypeI32, ssa.TypeF32,
   179  					ssa.TypeI64, ssa.TypeF64,
   180  				},
   181  			},
   182  			exp: abiImpl{
   183  				args: []backend.ABIArg{
   184  					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
   185  					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
   186  					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
   187  					{Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
   188  					{Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
   189  					{Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
   190  					{Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
   191  					{Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
   192  					{Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
   193  					{Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
   194  					{Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
   195  					{Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
   196  					{Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
   197  					{Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
   198  					{Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
   199  					{Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
   200  				},
   201  				rets: []backend.ABIArg{
   202  					{Index: 0, Kind: backend.ABIArgKindReg, Reg: x0VReg, Type: ssa.TypeI32},
   203  					{Index: 1, Kind: backend.ABIArgKindReg, Reg: v0VReg, Type: ssa.TypeF32},
   204  					{Index: 2, Kind: backend.ABIArgKindReg, Reg: x1VReg, Type: ssa.TypeI64},
   205  					{Index: 3, Kind: backend.ABIArgKindReg, Reg: v1VReg, Type: ssa.TypeF64},
   206  					{Index: 4, Kind: backend.ABIArgKindReg, Reg: x2VReg, Type: ssa.TypeI32},
   207  					{Index: 5, Kind: backend.ABIArgKindReg, Reg: v2VReg, Type: ssa.TypeF32},
   208  					{Index: 6, Kind: backend.ABIArgKindReg, Reg: x3VReg, Type: ssa.TypeI64},
   209  					{Index: 7, Kind: backend.ABIArgKindReg, Reg: v3VReg, Type: ssa.TypeF64},
   210  					{Index: 8, Kind: backend.ABIArgKindReg, Reg: x4VReg, Type: ssa.TypeI32},
   211  					{Index: 9, Kind: backend.ABIArgKindReg, Reg: v4VReg, Type: ssa.TypeF32},
   212  					{Index: 10, Kind: backend.ABIArgKindReg, Reg: x5VReg, Type: ssa.TypeI64},
   213  					{Index: 11, Kind: backend.ABIArgKindReg, Reg: v5VReg, Type: ssa.TypeF64},
   214  					{Index: 12, Kind: backend.ABIArgKindReg, Reg: x6VReg, Type: ssa.TypeI32},
   215  					{Index: 13, Kind: backend.ABIArgKindReg, Reg: v6VReg, Type: ssa.TypeF32},
   216  					{Index: 14, Kind: backend.ABIArgKindReg, Reg: x7VReg, Type: ssa.TypeI64},
   217  					{Index: 15, Kind: backend.ABIArgKindReg, Reg: v7VReg, Type: ssa.TypeF64},
   218  				},
   219  				retRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg},
   220  				argRealRegs: []regalloc.VReg{x0VReg, v0VReg, x1VReg, v1VReg, x2VReg, v2VReg, x3VReg, v3VReg, x4VReg, v4VReg, x5VReg, v5VReg, x6VReg, v6VReg, x7VReg, v7VReg},
   221  			},
   222  		},
   223  	} {
   224  		tc := tc
   225  		t.Run(tc.name, func(t *testing.T) {
   226  			abi := abiImpl{}
   227  			abi.init(tc.sig)
   228  			require.Equal(t, tc.exp.args, abi.args)
   229  			require.Equal(t, tc.exp.rets, abi.rets)
   230  			require.Equal(t, tc.exp.argStackSize, abi.argStackSize)
   231  			require.Equal(t, tc.exp.retStackSize, abi.retStackSize)
   232  			require.Equal(t, tc.exp.retRealRegs, abi.retRealRegs)
   233  			require.Equal(t, tc.exp.argRealRegs, abi.argRealRegs)
   234  		})
   235  	}
   236  }
   237  
   238  func TestMachine_insertAddOrSubStackPointer(t *testing.T) {
   239  	t.Run("add/small", func(t *testing.T) {
   240  		_, _, m := newSetupWithMockContext()
   241  		m.insertAddOrSubStackPointer(spVReg, 0x10, true)
   242  		require.Equal(t, `add sp, sp, #0x10`, formatEmittedInstructionsInCurrentBlock(m))
   243  	})
   244  	t.Run("add/large stack", func(t *testing.T) {
   245  		_, _, m := newSetupWithMockContext()
   246  		m.insertAddOrSubStackPointer(spVReg, 0xffffffff_8, true)
   247  		require.Equal(t, `orr x27, xzr, #0xffffffff8
   248  add sp, sp, x27`, formatEmittedInstructionsInCurrentBlock(m))
   249  	})
   250  	t.Run("sub/small", func(t *testing.T) {
   251  		_, _, m := newSetupWithMockContext()
   252  		m.insertAddOrSubStackPointer(spVReg, 0x10, false)
   253  		require.Equal(t, `sub sp, sp, #0x10`, formatEmittedInstructionsInCurrentBlock(m))
   254  	})
   255  	t.Run("sub/large stack", func(t *testing.T) {
   256  		_, _, m := newSetupWithMockContext()
   257  		m.insertAddOrSubStackPointer(spVReg, 0xffffffff_8, false)
   258  		require.Equal(t, `orr x27, xzr, #0xffffffff8
   259  sub sp, sp, x27`, formatEmittedInstructionsInCurrentBlock(m))
   260  	})
   261  }
   262  
   263  func TestAbiImpl_callerGenVRegToFunctionArg_constant_inlining(t *testing.T) {
   264  	_, builder, m := newSetupWithMockContext()
   265  
   266  	i64 := builder.AllocateInstruction().AsIconst64(10).Insert(builder)
   267  	f64 := builder.AllocateInstruction().AsF64const(3.14).Insert(builder)
   268  	abi := m.getOrCreateABIImpl(&ssa.Signature{Params: []ssa.Type{ssa.TypeI64, ssa.TypeF64}})
   269  	abi.callerGenVRegToFunctionArg(0, regalloc.VReg(100).SetRegType(regalloc.RegTypeInt), &backend.SSAValueDefinition{Instr: i64, RefCount: 1}, 0)
   270  	abi.callerGenVRegToFunctionArg(1, regalloc.VReg(50).SetRegType(regalloc.RegTypeFloat), &backend.SSAValueDefinition{Instr: f64, RefCount: 1}, 0)
   271  	require.Equal(t, `movz x100?, #0xa, lsl 0
   272  mov x0, x100?
   273  ldr d50?, #8; b 16; data.f64 3.140000
   274  mov v0.8b, v50?.8b`, formatEmittedInstructionsInCurrentBlock(m))
   275  }