github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/arm64/machine_test.go (about)

     1  package arm64
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend"
     7  	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
     8  	"github.com/tetratelabs/wazero/internal/testing/require"
     9  )
    10  
    11  func TestMachine_resolveAddressingMode(t *testing.T) {
    12  	t.Run("imm12/arg", func(t *testing.T) {
    13  		m := &machine{}
    14  		i := &instruction{}
    15  		i.asULoad(operandNR(x17VReg), addressMode{
    16  			kind: addressModeKindArgStackSpace,
    17  			rn:   spVReg,
    18  			imm:  128,
    19  		}, 64)
    20  		m.resolveAddressingMode(1024, 0, i)
    21  		require.Equal(t, addressModeKindRegUnsignedImm12, i.amode.kind)
    22  		require.Equal(t, int64(128+1024), i.amode.imm)
    23  	})
    24  	t.Run("imm12/result", func(t *testing.T) {
    25  		m := &machine{}
    26  		i := &instruction{}
    27  		i.asULoad(operandNR(x17VReg), addressMode{
    28  			kind: addressModeKindResultStackSpace,
    29  			rn:   spVReg,
    30  			imm:  128,
    31  		}, 64)
    32  		m.resolveAddressingMode(0, 256, i)
    33  		require.Equal(t, addressModeKindRegUnsignedImm12, i.amode.kind)
    34  		require.Equal(t, int64(128+256), i.amode.imm)
    35  	})
    36  
    37  	t.Run("tmp reg", func(t *testing.T) {
    38  		m := &machine{executableContext: newExecutableContext()}
    39  		root := &instruction{kind: udf}
    40  		i := &instruction{prev: root}
    41  		i.asULoad(operandNR(x17VReg), addressMode{
    42  			kind: addressModeKindResultStackSpace,
    43  			rn:   spVReg,
    44  		}, 64)
    45  		m.resolveAddressingMode(0, 0x40000001, i)
    46  
    47  		m.executableContext.RootInstr = root
    48  		require.Equal(t, `
    49  	udf
    50  	movz x27, #0x1, lsl 0
    51  	movk x27, #0x4000, lsl 16
    52  	ldr x17, [sp, x27]
    53  `, m.Format())
    54  	})
    55  }
    56  
    57  func TestMachine_clobberedRegSlotSize(t *testing.T) {
    58  	m := &machine{clobberedRegs: make([]regalloc.VReg, 10)}
    59  	require.Equal(t, int64(160), m.clobberedRegSlotSize())
    60  }
    61  
    62  func TestMachine_frameSize(t *testing.T) {
    63  	m := &machine{clobberedRegs: make([]regalloc.VReg, 10), spillSlotSize: 16 * 8}
    64  	require.Equal(t, int64(16*18), m.frameSize())
    65  }
    66  
    67  func TestMachine_requiredStackSize(t *testing.T) {
    68  	m := &machine{
    69  		clobberedRegs: make([]regalloc.VReg, 10), spillSlotSize: 16 * 8,
    70  		maxRequiredStackSizeForCalls: 320,
    71  	}
    72  	require.Equal(t, int64(16*18)+int64(320)+32, m.requiredStackSize())
    73  }
    74  
    75  func TestMachine_arg0OffsetFromSP(t *testing.T) {
    76  	m := &machine{clobberedRegs: make([]regalloc.VReg, 10), spillSlotSize: 16 * 8}
    77  	require.Equal(t, int64(16*18)+32, m.arg0OffsetFromSP())
    78  }
    79  
    80  func TestMachine_ret0OffsetFromSP(t *testing.T) {
    81  	m := &machine{
    82  		clobberedRegs: make([]regalloc.VReg, 10), spillSlotSize: 16 * 8,
    83  		currentABI: &backend.FunctionABI{ArgStackSize: 180},
    84  	}
    85  	require.Equal(t, int64(16*18)+32+180, m.ret0OffsetFromSP())
    86  }
    87  
    88  func TestMachine_getVRegSpillSlotOffsetFromSP(t *testing.T) {
    89  	m := &machine{spillSlots: make(map[regalloc.VRegID]int64)}
    90  	id := regalloc.VRegID(1)
    91  	offset := m.getVRegSpillSlotOffsetFromSP(id, 8)
    92  	require.Equal(t, int64(16), offset)
    93  	require.Equal(t, int64(8), m.spillSlotSize)
    94  	_, ok := m.spillSlots[id]
    95  	require.True(t, ok)
    96  
    97  	id = 100
    98  	offset = m.getVRegSpillSlotOffsetFromSP(id, 16)
    99  	require.Equal(t, int64(16+8), offset)
   100  	require.Equal(t, int64(24), m.spillSlotSize)
   101  	_, ok = m.spillSlots[id]
   102  	require.True(t, ok)
   103  }
   104  
   105  func TestMachine_insertConditionalJumpTrampoline(t *testing.T) {
   106  	for _, tc := range []struct {
   107  		brAtEnd             bool
   108  		expBefore, expAfter string
   109  	}{
   110  		{
   111  			brAtEnd: true,
   112  			expBefore: `
   113  L100:
   114  	b.eq L12345
   115  	b L888888888
   116  L200:
   117  	exit_sequence x0
   118  `,
   119  			expAfter: `
   120  L100:
   121  	b.eq L10000000
   122  	b L888888888
   123  L10000000:
   124  	b L12345
   125  L200:
   126  	exit_sequence x0
   127  `,
   128  		},
   129  		{
   130  			brAtEnd: false,
   131  			expBefore: `
   132  L100:
   133  	b.eq L12345
   134  	udf
   135  L200:
   136  	exit_sequence x0
   137  `,
   138  			expAfter: `
   139  L100:
   140  	b.eq L10000000
   141  	udf
   142  	b L200
   143  L10000000:
   144  	b L12345
   145  L200:
   146  	exit_sequence x0
   147  `,
   148  		},
   149  	} {
   150  		var name string
   151  		if tc.brAtEnd {
   152  			name = "brAtEnd"
   153  		} else {
   154  			name = "brNotAtEnd"
   155  		}
   156  
   157  		t.Run(name, func(t *testing.T) {
   158  			m := NewBackend().(*machine)
   159  			const (
   160  				originLabel     = 100
   161  				originLabelNext = 200
   162  				targetLabel     = 12345
   163  			)
   164  
   165  			cbr := m.allocateInstr()
   166  			cbr.asCondBr(eq.asCond(), targetLabel, false)
   167  
   168  			end := m.allocateInstr()
   169  			if tc.brAtEnd {
   170  				end.asBr(888888888)
   171  			} else {
   172  				end.asUDF()
   173  			}
   174  
   175  			originalEndNext := m.allocateInstr()
   176  			originalEndNext.asExitSequence(x0VReg)
   177  
   178  			ectx := m.executableContext
   179  
   180  			originLabelPos := ectx.AllocateLabelPosition(originLabel)
   181  			originLabelPos.Begin = cbr
   182  			originLabelPos.End = linkInstr(cbr, end)
   183  			originNextLabelPos := ectx.AllocateLabelPosition(originLabelNext)
   184  			originNextLabelPos.Begin = originalEndNext
   185  			linkInstr(originLabelPos.End, originalEndNext)
   186  
   187  			ectx.LabelPositions[originLabel] = originLabelPos
   188  			ectx.LabelPositions[originLabelNext] = originNextLabelPos
   189  
   190  			ectx.RootInstr = cbr
   191  			require.Equal(t, tc.expBefore, m.Format())
   192  
   193  			ectx.NextLabel = 9999999
   194  			m.insertConditionalJumpTrampoline(cbr, originLabelPos, originLabelNext)
   195  
   196  			require.Equal(t, tc.expAfter, m.Format())
   197  
   198  			// The original label position should be updated to the unconditional jump to the original target destination.
   199  			require.Equal(t, "b L12345", originLabelPos.End.String())
   200  		})
   201  	}
   202  }