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 }