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 }