github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/engine/wazevo/backend/isa/arm64/machine_test.go (about)

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